Univariate analiza malihih preduzeća (nastavak)

Potrebno je pre svega razdvojiti uzorak na validacioni i estimacioni. U nacelu pravilo je da se uzorak deli na 70:30 na stranu estimacije,i u slucaju malih preduzeca to cemo i koristiti. Pa, pocnimo.

#izracunam broj redova
broj.red.small<-nrow(small)
broj.difolta.small<-sum(as.numeric(small$default.y==1))
procenat.difolta<-broj.difolta.small/broj.red.small
set.seed(45)
#zbog reprodukcije
sample.small <-
sample(broj.red.small, size = round(0.75 * broj.red.small, 0))
small.training <- small[sample.small, ]
small.test <- small[-sample.small, ]

Testiranje radne hipoteze, diskriminativnosti, korelacione matrice

Jos jednom cemo pregledati varijable:

#rpivotTable(lrge.training)
summary_table.small<-t(sapply(small.training[,11:43],my.summary,arg=T))
tr_summary_table.small<-t(summary_table.small)
formatRound(
            datatable(
                      summary_table.small,caption = "Tabela 3.:Sumarni prikaz",
                      filter = 'none'
                      ),
            columns = colnames(summary_table.small)
           )

Generalna preporuka je da se radna hipoteza testira pre tretmana nedostajućih vrednosti budući da će se nedostajuće vrednosti popunjavati uslovno od stanja solventnosti duznika. Samim tim ovde cemo kao prvi vid selekcije ispitati radnu hipotezu kako kontinualnih tako i kategorickih varijabli. Počećemo sa kontinualnim1 i analizu raditi u paru sa proverom diskriminativnosti varijabli. Još u Tabeli 3 vidimo velika odstupanja srednje vrednosti od medijane i trimovanog proseka, buduci da je prosek kao mera centralne tendencije osetljiva na autlajere odlucujemo se da posmatramo medijanu i trimovan prosek, samim tim mogucnost t testa otpada. Dalje, sledeci preporuke iz literature ovaj deo analize osloniti na posmatranje box plotova i bice dopunjen diskriminativnom analizom AUROC-a. Pri testiranju korelacija prag selekcije postavljamo na 0.5 i od dve biramo onu varijablu koja ima vecu diskriminacionu moc.

Kod kategorickih varijabli posmatracemo tabele frekvencija tamo gde to bude imalo smisla i sprovesti Chi-squared test. Ovom prilikom potrebno je i pregrupisati ove varijable tako da budu zadovoljeni kriterijumi:

Prvo pregledajmo samu distribuciju jos jednom, mada su neke stvari vec jasne iz Tabele 3 hajde ipak da pogledamo.
Prvo kreiramo funkciju za plotiranje: qq plota, box plota, poredjenja gustina verovatnoce (kernela empiriskih distribucija verovatnoce) i konacno za proveru diskriminacije ROC krive.

#delimo uzorak na kontinualne i kategoricke
small.training.continualne<-small.training[,c(7,6,11,13:43)]
small.training.kategoricke<-small.training[,c(7,8,9,10,12)]
small.test.continualne<-small.test[,c(7,6,11,13:43)]
small.test.kategoricke<-small.test[,c(7,8,9,10,12)]

Krećemo sa opisom svake varijable ponaosob:

Neprekidne promenljive:

Udeo ispravke u ukupnim kreditima


#definisem funkciju za plotovanje
ploting(small.training,6,7)
Ignoring unknown parameters: positionRemoved 1796 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-nismo postavili radnu hipotezu za ovu varijablu
  • Diskriminativnost - postoji na 95% sigurnosti
  • autlajeri - naravno ima ih ima
  • normalnost - ma da…

Broj zaposlenih


#definisem funkciju za plotovanje
ploting(small.training,11,7)
Ignoring unknown parameters: positionRemoved 2621 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-nismo postavili radnu hipotezu za ovu varijablu
  • Diskriminativnost - ima je
  • autlajeri - naravno ima ih
  • normalnost - ma da…

Rigorozni racio redukovane (monetarne) likvidnosti


#definisem funkciju za plotovanje
ploting(small.training,13,7)
Ignoring unknown parameters: positionRemoved 3268 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-zadovoljena, veci difolt kod manjih vrednosti
  • Diskriminativnost - ima na 95% znacajnosti
  • autlajeri - naravno ima ih
  • normalnost - ma da…

Racio novcane likvidnosti (Cash_ratio)


#definisem funkciju za plotovanje
ploting(small.training,14,7)
Ignoring unknown parameters: positionRemoved 3208 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-zadovoljena, veci difolt kod manjih vrednosti
  • Diskriminativnost - ima na 95% znacajnosti
  • autlajeri - naravno ima ih
  • normalnost - ma da…

Opsti racio likvidnosti


#definisem funkciju za plotovanje
ploting(small.training,15,7)
Ignoring unknown parameters: positionRemoved 3552 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-nezadovoljena, veci difolt kod vecih vrednosti
  • Diskriminativnost - ima na 95% znacajnosti ali je mala, uzimacemo samo preko 55%
  • autlajeri - naravno ima ih
  • normalnost - ma da…

Stepen_zaduzenosti


#definisem funkciju za plotovanje
ploting(small.training,16,7)
Ignoring unknown parameters: positionRemoved 1723 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-zadovoljena, veci difolt kod vecih vrednosti
  • Diskriminativnost - ima
  • autlajeri - naravno ima ih
  • normalnost - ma da…

Interest Coverage Ratio


#definisem funkciju za plotovanje
ploting(small.training,17,7)
Ignoring unknown parameters: positionRemoved 3558 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-zadovoljena, veci difolt kod manjih vrednosti
  • Diskriminativnost - ima
  • autlajeri - naravno ima ih
  • normalnost - ma da, ali bar lici na nesto normalno…

Racio pokrica obrtne imovine


#definisem funkciju za plotovanje
ploting(small.training,18,7)
Ignoring unknown parameters: positionRemoved 3590 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-zadovoljena, veci difolt kod manjih vrednosti
  • Diskriminativnost - ima
  • autlajeri - naravno ima ih
  • normalnost - ma da

Racio obrta potrazivanja od kupaca


#definisem funkciju za plotovanje
ploting(small.training,19,7)
Ignoring unknown parameters: positionRemoved 3058 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-zadovoljena, veci difolt kod manjih vrednosti
  • Diskriminativnost - ima
  • autlajeri - naravno ima ih
  • normalnost - ma da, vise kao \(\tilde\chi^2\)nost hihihi, kapiras hi kao hi distribucija :) …

Racio obrta poslovne imovine


#definisem funkciju za plotovanje
ploting(small.training,20,7)
Ignoring unknown parameters: positionRemoved 3104 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-zadovoljena, veci difolt kod manjih vrednosti
  • Diskriminativnost - ima
  • autlajeri - naravno ima ih
  • normalnost - ma da…

Gotovinski ciklus 1


#definisem funkciju za plotovanje
ploting(small.training,21,7)
Ignoring unknown parameters: positionRemoved 3336 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-nezadovoljena, veci difolt kod manjih vrednosti
  • Diskriminativnost - ima
  • autlajeri - naravno ima ih
  • normalnost - ma da…

Vreme vezivanja zaliha


#definisem funkciju za plotovanje
ploting(small.training,22,7)
Ignoring unknown parameters: positionRemoved 3398 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-zadovoljena, veci difolt kod vecih vrednosti
  • Diskriminativnost - ima
  • autlajeri - naravno ima ih
  • normalnost - ma da…

Vreme kreditiranja kupaca


#definisem funkciju za plotovanje
ploting(small.training,23,7)
Ignoring unknown parameters: positionRemoved 3470 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-zadovoljena, veci difolt kod vecih vrednosti
  • Diskriminativnost - ima
  • autlajeri - naravno ima ih
  • normalnost - ma da…

Vreme naplate potraživanja


#definisem funkciju za plotovanje
ploting(small.training,24,7)
Ignoring unknown parameters: positionRemoved 3536 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-zadovoljena, veca stopa difolta kod vecih vrednosti
  • Diskriminativnost - ima
  • autlajeri - naravno ima ih
  • normalnost - ma da…

Vreme plaćanja dobavljačima


#definisem funkciju za plotovanje
ploting(small.training,25,7)
Ignoring unknown parameters: positionRemoved 3454 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-nezadovoljena, veci difolt kod manjih vrednosti, ipak cemo je uzeti, jer može ekonomski da se objasni rezultat
  • Diskriminativnost - ima
  • autlajeri - naravno ima ih
  • normalnost - ma da…

Asset turnover


#definisem funkciju za plotovanje
ploting(small.training,26,7)
Ignoring unknown parameters: positionRemoved 3592 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-zadovoljena, veca verovatnoca difolta kod manje medijane
  • Diskriminativnost - ima
  • autlajeri - naravno ima ih
  • normalnost - ma da…

Rast EBITDA


#definisem funkciju za plotovanje
ploting(small.training,27,7)
Ignoring unknown parameters: positionRemoved 3092 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-zadovoljena, veca verovatnoca difolta kod manje medijane
  • Diskriminativnost - ima
  • autlajeri - naravno ima ih
  • normalnost - ma da…

Stopa prinosa na sopstveni kapital pre oporezivanja


#definisem funkciju za plotovanje
ploting(lrge.training,28,7)
Ignoring unknown parameters: positionRemoved 120 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-ne znam koji mu je djavo ali evo ovde cemo medijana zdravog je -86.0846544 a nesolventnog je -92.9856293 sto odgovara radnoj hipotezi veci difolt kod manjih vrednosti
  • Diskriminativnost - ima
  • autlajeri - naravno ima ih
  • normalnost - ma da…

Stopa prinosa na ukupna sredstva pre oporezivanja


#definisem funkciju za plotovanje
ploting(small.training,29,7)
Ignoring unknown parameters: positionRemoved 3592 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-ne znam koji mu je djavo ali evo ovde cemo medijana zdravog je -97.142369 a nesolventnog je -99.5386016 sto odgovara radnoj hipotezi
  • Diskriminativnost -ima
  • autlajeri - naravno ima ih
  • normalnost - jedan od blizih…

Basic Earnings Power Ratio


#definisem funkciju za plotovanje
ploting(small.training,30,7)
Ignoring unknown parameters: positionRemoved 3592 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-zadovoljena je, veci difolt sa manjom vrednoscu
  • Diskriminativnost - ima
  • autlajeri - naravno ima ih
  • normalnost - jook…

Rast prihoda od prodaje


#definisem funkciju za plotovanje
ploting(small.training,31,7)
Ignoring unknown parameters: positionRemoved 3054 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-zadovoljena je veci difolt kod manjih vrednosti
  • Diskriminativnost - ima
  • autlajeri - naravno ima ih
  • normalnost - jook…

Pokriće neto kamata


#definisem funkciju za plotovanje
ploting(small.training,32,7)
Ignoring unknown parameters: positionRemoved 2966 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-zadovoljena je manja vrednost veca verovatnoca difolta
  • Diskriminativnost - ima
  • autlajeri - naravno ima ih
  • normalnost - jook…

Cena tuđih izvora sredstava


#definisem funkciju za plotovanje
ploting(lrge.training,33,7,n=1)
Ignoring unknown parameters: positionRemoved 126 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-zadovoljena je veci difolt kod vecih vrednosti
  • Diskriminativnost - ima
  • autlajeri - naravno ima ih
  • normalnost - jook…

T1


#definisem funkciju za plotovanje
ploting(small.training,34,7)
Ignoring unknown parameters: positionRemoved 3592 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-zadovoljena je
  • Diskriminativnost - ima
  • autlajeri - naravno ima ih
  • normalnost - jook…

T2


#definisem funkciju za plotovanje
ploting(small.training,35,7)
Ignoring unknown parameters: positionRemoved 1796 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-zadovoljena je
  • Diskriminativnost - ima
  • autlajeri - naravno ima ih
  • normalnost - jook…

T3


#definisem funkciju za plotovanje
ploting(small.training,36,7)
Ignoring unknown parameters: positionRemoved 3592 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-zadovoljena je
  • Diskriminativnost - ima
  • autlajeri - naravno ima ih
  • normalnost - jook…

T4


#definisem funkciju za plotovanje
ploting(small.training,37,7)
Ignoring unknown parameters: positionRemoved 3394 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-zadovoljena je
  • Diskriminativnost - masterpiece
  • autlajeri - naravno ima ih
  • normalnost - jook…

T5


#definisem funkciju za plotovanje
ploting(small.training,38,7)
Ignoring unknown parameters: positionRemoved 3592 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-zadovoljena je
  • Diskriminativnost - ima
  • autlajeri - naravno ima ih
  • normalnost - jook…

T21


#definisem funkciju za plotovanje
ploting(small.training,39,7)
Ignoring unknown parameters: positionRemoved 3592 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-nezadovoljena
  • Diskriminativnost - nema, za malo
  • autlajeri - naravno ima ih
  • normalnost - jook…

Altman Z-score 1


#definisem funkciju za plotovanje
ploting(small.training,40,7)
Ignoring unknown parameters: positionRemoved 3394 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-zadovoljena je
  • Diskriminativnost - masterpiece
  • autlajeri - naravno ima ih
  • normalnost - jook…

Altman Z-score 2


#definisem funkciju za plotovanje
ploting(small.training,41,7)
Ignoring unknown parameters: positionRemoved 3394 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-zadovoljena je
  • Diskriminativnost - ima
  • autlajeri - naravno ima ih
  • normalnost - jook…

Altman Z-score 3


#definisem funkciju za plotovanje
ploting(small.training,42,7)
Ignoring unknown parameters: positionRemoved 3394 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-zadovoljena je
  • Diskriminativnost - masterpiece
  • autlajeri - naravno ima ih
  • normalnost - jook…

Udeo u kapitalu banke


#definisem funkciju za plotovanje
ploting(small.training,43,7)
Ignoring unknown parameters: positionRemoved 3592 rows containing non-finite values (stat_density).D not labeled 0/1, assuming 1 = 0 and 2 = 1!

  • Radna hipoteza-zadovoljena je, veci udeo losiji su u proseku
  • Diskriminativnost - za vece vrednosti da
  • autlajeri - naravno ima ih
  • normalnost - jook…

Korelaciona matrica

U tabeli 5. ispod vidimo da najvecu diskriminacionu moc poseduje varijabla T14 odmah iza koje je ALtman 1.

#proracun
cor=cor(small.training.continualne[,c(-1,-31,-32,-33)], use = "complete.obs")
#dodajemo AUROC kao dodatnu kolonu pored varijable
corr_summary.small <- function (predictor) {
  response = factor(small.training.continualne[[1]])
  suppressMessages(auc(response, as.numeric(predictor)))
}
auc_sumarno.small<-sapply(small.training.continualne[,c(-1,-31,-32,-33)], corr_summary.small)
kor_diskr.small<-(cbind(auc_sumarno.small,cor)) 
formatRound(
            datatable(
                      kor_diskr.small,caption = "Tabela 5.:Sumarni prikaz",
                      filter = 'none'
                      ),
            columns = colnames(kor_diskr.small)
           )

as.data.frame(kor_diskr.small)

Ovde kreiram funkciju koja ce da filtrira varijable po kriterijumu korelacije. Naime, po ugledu na 2 kao kriterijum granice koeficijenta korelacije preko koje ne bismo smeli prelaziti uzecemo vrednost od 0.5 koji ce u sprezi sa AUROC vrednosti selektirati jednu od dve varijable. Konacan izbor varijabli se vidi u korelacionoj tabeli ispod.

#assuming that table is n x (n+1) matrix where first column is AUROC value and the rest n x n is correlation matrix 
clean_cor.small<-corr_ellimination(kor_diskr.small)
knitr::kable(clean_cor.small, caption = "Tabela 6. skracena korelaciona tabela koja sadrzi varijable nad kojima ce se vrsiti dalja analiza")
AUROC Stopa_prinosa_na_ukupna_sredstva_pre_oporezivanja T14 T12 Racio_novcane_likvidnosti_(Cash_ratio) Asset_turnover Racio_pokrica_obrtne_imovine Stepen_zaduzenosti udeo_u_kapitalu Racio_pokrica_kamata_zaradom_pre_kamata_i_poreza_(Interest_Coverage_Ratio) Vreme_placanja_dobavljacima Vreme_naplate_potrazivanja Stopa_prinosa_na_sopstveni_kapital_pre_oporezivanja Pokrice_neto_kamata Rast_EBITDA Racio_obrta_potrazivanja_od_kupaca Vreme_kreditiranja_kupaca Gotovinski_ciklus_1 Broj_zaposlenih
Stopa_prinosa_na_ukupna_sredstva_pre_oporezivanja 0.7147068 1.0000000 0.1165590 0.4341258 0.1128484 0.1958647 0.0502256 -0.0263482 -0.0463149 0.0525652 -0.0062347 -0.0199984 0.0839210 -0.0157552 0.0348603 0.0172483 -0.0206373 0.0159378 0.0024429
T14 0.6973945 0.1165590 1.0000000 0.2611100 0.4795674 -0.0360332 0.0291147 -0.0122102 -0.0179755 0.0709050 -0.0010359 0.0198123 0.0028667 0.0012714 -0.0017285 0.0048825 -0.0020000 0.0166443 0.0058777
T12 0.6826563 0.4341258 0.2611100 1.0000000 0.1604509 0.0327279 0.0874663 -0.0455573 -0.0625975 0.0418614 -0.0109842 -0.0128638 0.0135095 -0.0002496 0.0004469 0.0132799 -0.0075940 0.0450543 -0.0570053
Racio_novcane_likvidnosti_(Cash_ratio) 0.6626892 0.1128484 0.4795674 0.1604509 1.0000000 0.0040580 0.0166795 -0.0052041 0.0028099 0.0210549 -0.0010279 -0.0036502 0.0032425 0.0085779 0.0031441 0.0291830 -0.0035404 0.0066690 -0.0071846
Asset_turnover 0.6606203 0.1958647 -0.0360332 0.0327279 0.0040580 1.0000000 0.0542484 -0.0028212 -0.0600007 -0.0064448 -0.0085182 -0.0413325 0.0194380 0.0055620 -0.0029900 0.0304797 -0.0424542 0.0057830 -0.0077756
Racio_pokrica_obrtne_imovine 0.6564486 0.0502256 0.0291147 0.0874663 0.0166795 0.0542484 1.0000000 -0.0156468 -0.0197482 0.0033306 -0.0728406 -0.0241162 0.0114168 -0.0008814 -0.0000493 -0.0010631 -0.0111443 0.0418198 0.0064618
Stepen_zaduzenosti 0.6424143 -0.0263482 -0.0122102 -0.0455573 -0.0052041 -0.0028212 -0.0156468 1.0000000 0.0061415 -0.0021876 0.0002599 0.0035013 -0.4251569 0.0008968 0.0104463 -0.0011129 0.0021755 -0.0045131 -0.0089361
udeo_u_kapitalu 0.6266576 -0.0463149 -0.0179755 -0.0625975 0.0028099 -0.0600007 -0.0197482 0.0061415 1.0000000 0.0053304 -0.0000342 0.0183950 -0.0031334 -0.0108029 0.0044632 0.0010618 0.0185163 -0.0005606 0.0252817
Racio_pokrica_kamata_zaradom_pre_kamata_i_poreza_(Interest_Coverage_Ratio) 0.6165062 0.0525652 0.0709050 0.0418614 0.0210549 -0.0064448 0.0033306 -0.0021876 0.0053304 1.0000000 -0.0000778 0.0047461 0.0039572 0.0361806 0.0030683 -0.0008095 0.0252395 0.0055216 0.0063174
Vreme_placanja_dobavljacima 0.6159324 -0.0062347 -0.0010359 -0.0109842 -0.0010279 -0.0085182 -0.0728406 0.0002599 -0.0000342 -0.0000778 1.0000000 0.0081789 -0.0001728 -0.0002227 0.0000988 -0.0004297 0.0042198 -0.0542947 -0.0050480
Vreme_naplate_potrazivanja 0.6154063 -0.0199984 0.0198123 -0.0128638 -0.0036502 -0.0413325 -0.0241162 0.0035013 0.0183950 0.0047461 0.0081789 1.0000000 -0.0026687 -0.0001631 -0.0005822 -0.0025271 0.3153157 -0.0838092 -0.0141436
Stopa_prinosa_na_sopstveni_kapital_pre_oporezivanja 0.6001106 0.0839210 0.0028667 0.0135095 0.0032425 0.0194380 0.0114168 -0.4251569 -0.0031334 0.0039572 -0.0001728 -0.0026687 1.0000000 -0.0021279 0.0022940 0.0008047 -0.0019686 0.0041697 -0.0028191
Pokrice_neto_kamata 0.5986841 -0.0157552 0.0012714 -0.0002496 0.0085779 0.0055620 -0.0008814 0.0008968 -0.0108029 0.0361806 -0.0002227 -0.0001631 -0.0021279 1.0000000 -0.0002522 0.0015299 0.0013857 0.0006617 0.0020257
Rast_EBITDA 0.5949098 0.0348603 -0.0017285 0.0004469 0.0031441 -0.0029900 -0.0000493 0.0104463 0.0044632 0.0030683 0.0000988 -0.0005822 0.0022940 -0.0002522 1.0000000 0.0001519 -0.0007876 0.0021314 -0.0033808
Racio_obrta_potrazivanja_od_kupaca 0.5944460 0.0172483 0.0048825 0.0132799 0.0291830 0.0304797 -0.0010631 -0.0011129 0.0010618 -0.0008095 -0.0004297 -0.0025271 0.0008047 0.0015299 0.0001519 1.0000000 -0.0029311 0.0032876 0.0035148
Vreme_kreditiranja_kupaca 0.5870546 -0.0206373 -0.0020000 -0.0075940 -0.0035404 -0.0424542 -0.0111443 0.0021755 0.0185163 0.0252395 0.0042198 0.3153157 -0.0019686 0.0013857 -0.0007876 -0.0029311 1.0000000 -0.0060538 -0.0158706
Gotovinski_ciklus_1 0.5806210 0.0159378 0.0166443 0.0450543 0.0066690 0.0057830 0.0418198 -0.0045131 -0.0005606 0.0055216 -0.0542947 -0.0838092 0.0041697 0.0006617 0.0021314 0.0032876 -0.0060538 1.0000000 -0.0101120
Broj_zaposlenih 0.5734997 0.0024429 0.0058777 -0.0570053 -0.0071846 -0.0077756 0.0064618 -0.0089361 0.0252817 0.0063174 -0.0050480 -0.0141436 -0.0028191 0.0020257 -0.0033808 0.0035148 -0.0158706 -0.0101120 1.0000000

Tretman problematicnih varijabli

Ovako, generalno, ono sto nismo (nismo hteli komentarisati) komentarisali su simetricnosti varijabli. Pozitivno asimetricno je bar pola posmatranih varijabli tako da bi valjala neka vrsta logaritmovane transformacije uz vodjenje racuna o negativnim vrednostima (na primer transformacija tipa: \(\log(var + \min(var) + 1))\) bi se pobrinula za negativne vrednosti. Box Za negativnu asimetricnost bi koristili eventualno eksponencijalnu transformaciju. Videcemo posle prvog stepwisea i AUROC-a.

Ipak, ovde cemo se koncentrisati na par prethodno napomenutih varijabli.

Pokriće neto kamata

Prvo cemo podeliti varijablu na n intervala. Za optimalan broj intervala mozemo iskoristiti drugu funkciju koja ima algoritam koji bira broj intervala od 10 do 20 na osnovu odredjenih kriterijuma, vidi help funkcije dole.

#kreiram tabelu od pokrica neto kamata i indikatora default-a
data<-small.training[,c("default.y","Pokrice_neto_kamata")]
IV <- create_infotables(data=data,
                        y="default.y", 
                        parallel=FALSE)
IV_Value = data.frame(IV$Summary)
IV_Value
IV$Tables
$Pokrice_neto_kamata
plot_infotables(IV,"Pokrice_neto_kamata")

Dakle optimum je 10, imajuci u obzir nedostajuce vrednosti kao 11 kategoriju. Sada racunamo fiting funkciju transformacije. Generalno, mogli bismo podeliti varijablu u 8 kategorickih, ali ja bih izbegao to. Hajde prvo da vidimo empirijsku distribuciju, pa da fitujemo.

#izracunam medijanu po svakom binu

Kategoricke promenljive:

Postoje tri kategoricke varijable koje je potrebno analizirati:

rpivotTable(lrge.training.kategoricke,
            rows = "default.y", 
            cols = "Strani_investitor",
            aggregatorName = "Count as Fraction of Columns")

Sifra sektora:

freq_table=function(dta,kategorical,default){
  kategorical=as.name(kategorical)
  default=as.name(default)
  tmp=dta[,.N,by=.(eval(kategorical),eval(default))]
  frekvenca_sektor<-dcast(tmp,eval(kategorical)~eval(default),value.var="N")
  frekvenca_sektor$`0`[is.na(frekvenca_sektor$`0`)]=0
  frekvenca_sektor$`1`[is.na(frekvenca_sektor$`1`)]=0
  ukupno<-frekvenca_sektor$`0`+frekvenca_sektor$`1`
  frekvenca_sektor<-cbind.data.frame(frekvenca_sektor,ukupno)
  frekvenca_sektor[,default_rate:=frekvenca_sektor$`1`/ukupno]
  as.data.frame(frekvenca_sektor)
}
freq_table(small.training.kategoricke,"Sifra_sektor","default.y")
small.training.kategoricke$Sifra_sektor1[small.training.kategoricke$Sifra_sektor=="B"]<-"4%"
small.training.kategoricke$Sifra_sektor1[small.training.kategoricke$Sifra_sektor=="G"]<-"4%"
small.training.kategoricke$Sifra_sektor1[small.training.kategoricke$Sifra_sektor=="J"]<-"4%"
small.training.kategoricke$Sifra_sektor1[small.training.kategoricke$Sifra_sektor=="P"]<-"4%"
small.training.kategoricke$Sifra_sektor1[small.training.kategoricke$Sifra_sektor=="Q"]<-"4%"
small.training.kategoricke$Sifra_sektor1[small.training.kategoricke$Sifra_sektor=="R"]<-"4%"
small.test.kategoricke$Sifra_sektor1[small.test.kategoricke$Sifra_sektor=="B"]<-"4%"
small.test.kategoricke$Sifra_sektor1[small.test.kategoricke$Sifra_sektor=="G"]<-"4%"
small.test.kategoricke$Sifra_sektor1[small.test.kategoricke$Sifra_sektor=="J"]<-"4%"
small.test.kategoricke$Sifra_sektor1[small.test.kategoricke$Sifra_sektor=="P"]<-"4%"
small.test.kategoricke$Sifra_sektor1[small.test.kategoricke$Sifra_sektor=="Q"]<-"4%"
small.test.kategoricke$Sifra_sektor1[small.test.kategoricke$Sifra_sektor=="R"]<-"4%"
small.training.kategoricke$Sifra_sektor1[small.training.kategoricke$Sifra_sektor=="M"]<-"6%"
small.training.kategoricke$Sifra_sektor1[small.training.kategoricke$Sifra_sektor=="N"]<-"6%"
small.training.kategoricke$Sifra_sektor1[small.training.kategoricke$Sifra_sektor=="S"]<-"6%"
small.training.kategoricke$Sifra_sektor1[small.training.kategoricke$Sifra_sektor=="F"]<-"6%"
small.test.kategoricke$Sifra_sektor1[small.test.kategoricke$Sifra_sektor=="M"]<-"6%"
small.test.kategoricke$Sifra_sektor1[small.test.kategoricke$Sifra_sektor=="N"]<-"6%"
small.test.kategoricke$Sifra_sektor1[small.test.kategoricke$Sifra_sektor=="S"]<-"6%"
small.test.kategoricke$Sifra_sektor1[small.test.kategoricke$Sifra_sektor=="F"]<-"6%"
small.training.kategoricke$Sifra_sektor1[small.training.kategoricke$Sifra_sektor=="H"]<-"3%"
small.training.kategoricke$Sifra_sektor1[small.training.kategoricke$Sifra_sektor=="E"]<-"3%"
small.test.kategoricke$Sifra_sektor1[small.test.kategoricke$Sifra_sektor=="H"]<-"3%"
small.test.kategoricke$Sifra_sektor1[small.test.kategoricke$Sifra_sektor=="E"]<-"3%"
small.training.kategoricke$Sifra_sektor1[small.training.kategoricke$Sifra_sektor=="I"]<-"10%"
small.training.kategoricke$Sifra_sektor1[small.training.kategoricke$Sifra_sektor=="J"]<-"9%"
small.training.kategoricke$Sifra_sektor1[small.training.kategoricke$Sifra_sektor=="K"]<-"9%"
small.test.kategoricke$Sifra_sektor1[small.test.kategoricke$Sifra_sektor=="I"]<-"10%"
small.test.kategoricke$Sifra_sektor1[small.test.kategoricke$Sifra_sektor=="J"]<-"9%"
small.test.kategoricke$Sifra_sektor1[small.test.kategoricke$Sifra_sektor=="K"]<-"9%"
small.training.kategoricke$Sifra_sektor1[small.training.kategoricke$Sifra_sektor=="A"]<-"5%"
small.training.kategoricke$Sifra_sektor1[small.training.kategoricke$Sifra_sektor=="C"]<-"5%"
small.training.kategoricke$Sifra_sektor1[small.training.kategoricke$Sifra_sektor=="D"]<-"5%"
small.test.kategoricke$Sifra_sektor1[small.test.kategoricke$Sifra_sektor=="A"]<-"5%"
small.test.kategoricke$Sifra_sektor1[small.test.kategoricke$Sifra_sektor=="C"]<-"5%"
small.test.kategoricke$Sifra_sektor1[small.test.kategoricke$Sifra_sektor=="D"]<-"5%"
small.training.kategoricke$Sifra_sektor1[small.training.kategoricke$Sifra_sektor=="L"]<-"14%"
small.test.kategoricke$Sifra_sektor1[small.test.kategoricke$Sifra_sektor=="L"]<-"14%"
freq_table(small.training.kategoricke,"Sifra_sektor1","default.y")
data_sifra_sektor.small<-small.training.kategoricke[,c("default.y","Sifra_sektor1")]
IV_sifra_sektor.small<-create_infotables(data=data_sifra_sektor.small,
                        y="default.y", 
                        parallel=FALSE)
IV_sifra_sektor.small$Tables
$Sifra_sektor1
NA

Information value je bzveze, probajmo sada jos da pregrupišemo:

small.training.kategoricke$Sifra_sektor2[small.training.kategoricke$Sifra_sektor1=="10%"]<-"10%"
small.training.kategoricke$Sifra_sektor2[small.training.kategoricke$Sifra_sektor1=="14%"]<-"14%"
small.training.kategoricke$Sifra_sektor2[small.training.kategoricke$Sifra_sektor1=="9%"]<-"6-9%"
small.training.kategoricke$Sifra_sektor2[small.training.kategoricke$Sifra_sektor1=="6%"]<-"6-9%"
small.test.kategoricke$Sifra_sektor2[small.test.kategoricke$Sifra_sektor1=="10%"]<-"10%"
small.test.kategoricke$Sifra_sektor2[small.test.kategoricke$Sifra_sektor1=="14%"]<-"14%"
small.test.kategoricke$Sifra_sektor2[small.test.kategoricke$Sifra_sektor1=="9%"]<-"6-9%"
small.test.kategoricke$Sifra_sektor2[small.test.kategoricke$Sifra_sektor1=="6%"]<-"6-9%"
small.training.kategoricke$Sifra_sektor2[small.training.kategoricke$Sifra_sektor1=="5%"]<-"5%"
small.training.kategoricke$Sifra_sektor2[small.training.kategoricke$Sifra_sektor1=="4%"]<-"5%"
small.training.kategoricke$Sifra_sektor2[small.training.kategoricke$Sifra_sektor1=="3%"]<-"3%"
small.test.kategoricke$Sifra_sektor2[small.test.kategoricke$Sifra_sektor1=="5%"]<-"5%"
small.test.kategoricke$Sifra_sektor2[small.test.kategoricke$Sifra_sektor1=="4%"]<-"5%"
small.test.kategoricke$Sifra_sektor2[small.test.kategoricke$Sifra_sektor1=="3%"]<-"3%"
data_sifra_sektor.small<-small.training.kategoricke[,c("default.y","Sifra_sektor2")]
IV_sifra_sektor.small<-create_infotables(data=data_sifra_sektor.small,
                        y="default.y", 
                        parallel=FALSE)
IV_sifra_sektor.small$Tables
$Sifra_sektor2
NA

Zakljucujemo da, sektor kod malih i mikro preduzeca ne igra bas bitnu ulogu ali cemo uzeti ovu varijablu. ####Sifra opstine:

freq_table(small.training.kategoricke,"Sifra_opstine","default.y")

Za pocetak cemo smestiti sve opstine koje imaju manje od 100 duznika i manje od 5 difoltera u jednu klasu.

temp.table<-freq_table(small.training.kategoricke,"Sifra_opstine","default.y")
ostalo.small.names<-temp.table[temp.table$ukupno<100,1]
small.training.kategoricke$Sifra_opstine1<-small.training.kategoricke$Sifra_opstine
small.training.kategoricke$Sifra_opstine1[small.training.kategoricke$Sifra_opstine%in%ostalo.small.names]<-"ostalo"
small.test.kategoricke$Sifra_opstine1<-small.test.kategoricke$Sifra_opstine
small.test.kategoricke$Sifra_opstine1[small.test.kategoricke$Sifra_opstine%in%ostalo.small.names]<-"ostalo"
ostalo.small.names<-temp.table[temp.table$`1`<5,1]
small.training.kategoricke$Sifra_opstine1[small.training.kategoricke$Sifra_opstine%in%ostalo.small.names]<-"ostalo"
small.training.kategoricke$Sifra_opstine1[small.training.kategoricke$Sifra_opstine%in%ostalo.small.names]<-"ostalo"
small.test.kategoricke$Sifra_opstine1[small.test.kategoricke$Sifra_opstine%in%ostalo.small.names]<-"ostalo"
small.test.kategoricke$Sifra_opstine1[small.test.kategoricke$Sifra_opstine%in%ostalo.small.names]<-"ostalo"
temp.table<-freq_table(small.training.kategoricke,"Sifra_opstine1","default.y")
temp.table

Svstavamo ih po stopi difolta da vidimo da li se sta moze promeniti

small.training.kategoricke$Sifra_opstine2[small.training.kategoricke$Sifra_opstine1 %in%
                                            c(70041, 70955, 80403)] <- "2%"
small.test.kategoricke$Sifra_opstine2[small.test.kategoricke$Sifra_opstine1 %in%
                                            c(70041, 70955, 80403)] <- "2%"
small.training.kategoricke$Sifra_opstine2[small.training.kategoricke$Sifra_opstine1 %in%
                                            c(70653,71099,71242,79065,80128)] <- "3%"
small.test.kategoricke$Sifra_opstine2[small.test.kategoricke$Sifra_opstine1 %in%
                                            c(70653,71099,71242,79065,80128)] <- "3%"
small.training.kategoricke$Sifra_opstine2[small.training.kategoricke$Sifra_opstine1 %in% c(70033,70483,70904,71048,71269,79022,79057,80110,80438,80462,"ostalo")] <- "4%"
small.test.kategoricke$Sifra_opstine2[small.test.kategoricke$Sifra_opstine1 %in% c(70033,70483,70904,71048,71269,79022,79057,80110,80438,80462,"ostalo")] <- "4%"
small.test.kategoricke$Sifra_opstine2[small.test.kategoricke$Sifra_opstine1 %in%
c(89010,80466,80420,80357,80314,80195,80179,80152,80071,70670,70459,70360,70645)] <- "5%"
small.training.kategoricke$Sifra_opstine2[small.training.kategoricke$Sifra_opstine1 %in%
c(89010,80466,80420,80357,80314,80195,80179,80152,80071,70670,70459,70360,70645)] <- "5%"
small.training.kategoricke$Sifra_opstine2[small.training.kategoricke$Sifra_opstine1 %in%
c(70726,70734,71102,71200,79014,79049,80063,80446)] <- "6%"
small.test.kategoricke$Sifra_opstine2[small.test.kategoricke$Sifra_opstine1 %in%
c(70726,70734,71102,71200,79014,79049,80063,80446)] <- "6%"
small.training.kategoricke$Sifra_opstine2[small.training.kategoricke$Sifra_opstine1 %in%
c(70874,70564,70386,80381)] <- "7%"
small.test.kategoricke$Sifra_opstine2[small.test.kategoricke$Sifra_opstine1 %in%
c(70874,70564,70386,80381)] <- "7%"
small.test.kategoricke$Sifra_opstine2[small.test.kategoricke$Sifra_opstine1 %in%
c(80209,80233)] <- "8>%"
small.training.kategoricke$Sifra_opstine2[small.training.kategoricke$Sifra_opstine1 %in%
c(80209,80233)] <- "8>%"
data_sifra_ostine.small<-small.training.kategoricke[,c("default.y","Sifra_opstine2")]
IV_sifra_sektor<-create_infotables(data=data_sifra_ostine.small,
                        y="default.y", 
                        parallel=FALSE)
IV_sifra_sektor$Tables
$Sifra_opstine2
NA

probajmo da pregrupisemo

small.training.kategoricke$Sifra_opstine3<-small.training.kategoricke$Sifra_opstine2 
small.training.kategoricke$Sifra_opstine3[small.training.kategoricke$Sifra_opstine2 %in%
                                            c("4%","5%")] <- "4-5%"
small.test.kategoricke$Sifra_opstine3<-small.test.kategoricke$Sifra_opstine2 
small.test.kategoricke$Sifra_opstine3[small.test.kategoricke$Sifra_opstine2 %in%
                                            c("4%","5%")] <- "4-5%"
#small.training.kategoricke$Sifra_opstine3[(small.training.kategoricke$Sifra_opstine2 %in%
                                            #c("5%","6%","7%","8>%"))] <- "high%"
data_sifra_ostine.small2<-small.training.kategoricke[,c("default.y","Sifra_opstine3")]
IV_sifra_sektor2<-create_infotables(data=data_sifra_ostine.small2,
                        y="default.y", 
                        parallel=FALSE)
IV_sifra_sektor2$Tables        
$Sifra_opstine3
freq_table(small.training.kategoricke,"Sifra_opstine3","default.y")        

cak i ovako rasporedjene imaju slabu prediktivnu moc. pokusavamo sada po razvijenosti opstina, ovo necemo uzimati jer nema nekog logicnog objasnjenja a diskriminativnost i nije velika

IV_razvijenost2$Tables   
$Razvijenost
NA

beznacajno, konacan zakljucak je da idemo sa varijablom Sifra_opstine3 ####Strani investitor

Pogledajmo prvo frekvencionu tabelu

freq_table(small.training.kategoricke,"Strani_investitor","default.y")

Postoji razlika, imajuci u vidu da ovde imamo samo dve varijable, to je i ocekivano, hajde da vidimo IV:

WOETable(X=as.factor(small.training.kategoricke$Strani_investitor),Y=(small.training.kategoricke$default.y-1)*(-1))

nema uticaja

Velicina

WOETable(X=as.factor(small.training.kategoricke$Velicina),Y=(small.training.kategoricke$default.y-1)*(-1))

marginalno

Evaluacija regresije

Dosadasnji rezultati:

Otpadanje usled NA vrednosti, prezivele su sledece varijable:

preziveli.NA.small
 [1] "Broj_zaposlenih"                                                           
 [2] "Velicina"                                                                  
 [3] "Rigorozni_racio_redukovane_(monetarne)_likvidnosti"                        
 [4] "Opsti_racio_likvidnosti"                                                   
 [5] "Stepen_zaduzenosti"                                                        
 [6] "Racio_pokrica_kamata_zaradom_pre_kamata_i_poreza_(Interest_Coverage_Ratio)"
 [7] "Racio_pokrica_obrtne_imovine"                                              
 [8] "Gotovinski_ciklus_1"                                                       
 [9] "Vreme_vezivanja_zaliha"                                                    
[10] "Vreme_kreditiranja_kupaca"                                                 
[11] "Vreme_naplate_potrazivanja"                                                
[12] "Vreme_placanja_dobavljacima"                                               
[13] "Asset_turnover"                                                            
[14] "Stopa_prinosa_na_sopstveni_kapital_pre_oporezivanja"                       
[15] "Stopa_prinosa_na_ukupna_sredstva_pre_oporezivanja"                         
[16] "Basic_Earnings_Power_Ratio"                                                
[17] "Cena_tudjih_izvora_sredstava"                                              
[18] "T11"                                                                       
[19] "T12"                                                                       
[20] "T13"                                                                       
[21] "T14"                                                                       
[22] "T15"                                                                       
[23] "T21"                                                                       
[24] "Altman I"                                                                  
[25] "Altman emerging markets"                                                   
[26] "Altman private firms"                                                      
[27] "udeo_u_kapitalu"                                                           

Ciscenje usled korelacija i AUROC-a manjeg od 0.55

preziveli.corr.AUC.small
 [1] "Stopa_prinosa_na_ukupna_sredstva_pre_oporezivanja"                         
 [2] "T14"                                                                       
 [3] "T12"                                                                       
 [4] "Racio_novcane_likvidnosti_(Cash_ratio)"                                    
 [5] "Asset_turnover"                                                            
 [6] "Racio_pokrica_obrtne_imovine"                                              
 [7] "Stepen_zaduzenosti"                                                        
 [8] "udeo_u_kapitalu"                                                           
 [9] "Racio_pokrica_kamata_zaradom_pre_kamata_i_poreza_(Interest_Coverage_Ratio)"
[10] "Vreme_placanja_dobavljacima"                                               
[11] "Vreme_naplate_potrazivanja"                                                
[12] "Stopa_prinosa_na_sopstveni_kapital_pre_oporezivanja"                       
[13] "Pokrice_neto_kamata"                                                       
[14] "Rast_EBITDA"                                                               
[15] "Racio_obrta_potrazivanja_od_kupaca"                                        
[16] "Vreme_kreditiranja_kupaca"                                                 
[17] "Gotovinski_ciklus_1"                                                       
[18] "Broj_zaposlenih"                                                           

Presek ova dva nastavlja u multivariate.

odabrani.small
 [1] "Racio_novcane_likvidnosti_(Cash_ratio)"                                    
 [2] "Broj_zaposlenih"                                                           
 [3] "Stepen_zaduzenosti"                                                        
 [4] "Racio_pokrica_kamata_zaradom_pre_kamata_i_poreza_(Interest_Coverage_Ratio)"
 [5] "Racio_pokrica_obrtne_imovine"                                              
 [6] "Gotovinski_ciklus_1"                                                       
 [7] "Vreme_kreditiranja_kupaca"                                                 
 [8] "Vreme_naplate_potrazivanja"                                                
 [9] "Vreme_placanja_dobavljacima"                                               
[10] "Asset_turnover"                                                            
[11] "Stopa_prinosa_na_sopstveni_kapital_pre_oporezivanja"                       
[12] "Stopa_prinosa_na_ukupna_sredstva_pre_oporezivanja"                         
[13] "T12"                                                                       
[14] "T14"                                                                       
[15] "udeo_u_kapitalu"                                                           

Kreiramo zavrsni uzorak:


Tretman nedostajucih i tretman autlajera, potom dodajemo kategoricke

finalni_small<-small.training[,c(odabrani.small),with=F]
finalni_small.test<-small.test[,c(odabrani.small),with=F]
#finalni_lrge<-cbind.data.frame(finalni_lrge,Asset_turnover$Asset_turnover.tr,Pokrice_neto_kamata$Pokrice_neto_kamata.tr)
finalni_small<-as.data.table(sapply(finalni_small,replace_outlier_with_quantile))
finalni_small.test<-as.data.table(sapply(finalni_small.test,replace_outlier_with_quantile))
finalni_small$default.y<-small.training$default.y
finalni_small<-replace_missing_with_knn(finalni_small)
finalni_small$default.y<-NULL

opciono, transformacija

AA<-data.frame(1:nrow(finalni_small));n=1

for(i in names(finalni_small)["default.y" != names(finalni_small)]) {

  n = n + 1
  tmp <- calibrate_parameters(finalni_small, i, "default.y")
  AA <- cbind.data.frame(AA, tmp[[7]])
  names(AA)[n] <- names(finalni_small)[n]
}


finalni_small <- AA
remove(AA)
finalni_small[, 1] <- NULL
finalni_small$default.y <- default.y
finalni_small <- as.data.table(finalni_small)

Dodajemo dve kategoricke:

#spajamo sa kategorickim i skidamo par viskova kategorickih, velicina, total
finalni_small <-
  cbind.data.frame(finalni_small, small.training.kategoricke[, c("Velicina","Sifra_sektor2","Sifra_opstine3")])
finalni_small.test <-
  cbind.data.frame(finalni_small.test, small.test.kategoricke[, c("Velicina","Sifra_sektor2","Sifra_opstine3")])
#pretvaram kategoricke u faktor da bi ih glm posmatrao kao kategoricke
finalni_small$Sifra_sektor2 <- as.factor(finalni_small$Sifra_sektor2)
finalni_small$Velicina <-as.factor(finalni_small$Velicina)
finalni_small$Sifra_opstine3 <-as.factor(finalni_small$Sifra_opstine3)
finalni_small.test$Sifra_sektor2 <- as.factor(finalni_small.test$Sifra_sektor2)
finalni_small.test$Velicina <-as.factor(finalni_small.test$Velicina)
finalni_small.test$Sifra_opstine3 <-as.factor(finalni_small.test$Sifra_opstine3)

Dugo ocekivani trenutak:

model.null.small = glm(default.y ~ 1,
                 data=finalni_small,
                 family = binomial(link="logit")
                 )
model.full.small = glm(default.y ~ .,
                 data=finalni_small,
                 family = binomial(link="logit")
                 )
    
step(model.null.small,
     scope = list(upper=model.full.small,lower=model.null.small),
             direction="forward",
             
             data=finalni_small,trace=0)

Call:  glm(formula = default.y ~ T12 + Stopa_prinosa_na_ukupna_sredstva_pre_oporezivanja + 
    Asset_turnover + `Racio_novcane_likvidnosti_(Cash_ratio)` + 
    Sifra_opstine3 + udeo_u_kapitalu + Stepen_zaduzenosti + Vreme_kreditiranja_kupaca + 
    Sifra_sektor2 + `Racio_pokrica_kamata_zaradom_pre_kamata_i_poreza_(Interest_Coverage_Ratio)` + 
    Broj_zaposlenih + Racio_pokrica_obrtne_imovine + Velicina + 
    T14 + Stopa_prinosa_na_sopstveni_kapital_pre_oporezivanja, 
    family = binomial(link = "logit"), data = finalni_small)

Coefficients:
                                                                 (Intercept)  
                                                                  -5.6165874  
                                                                         T12  
                                                                  -2.7772841  
                           Stopa_prinosa_na_ukupna_sredstva_pre_oporezivanja  
                                                                  -0.0289081  
                                                              Asset_turnover  
                                                                  -0.1854926  
                                    `Racio_novcane_likvidnosti_(Cash_ratio)`  
                                                                  -1.6625834  
                                                            Sifra_opstine33%  
                                                                   0.3689998  
                                                          Sifra_opstine34-5%  
                                                                   0.6810619  
                                                            Sifra_opstine36%  
                                                                   0.9404356  
                                                            Sifra_opstine37%  
                                                                   0.9770421  
                                                           Sifra_opstine38>%  
                                                                   1.1036830  
                                                             udeo_u_kapitalu  
                                                                   0.0269230  
                                                          Stepen_zaduzenosti  
                                                                   0.0076335  
                                                   Vreme_kreditiranja_kupaca  
                                                                   0.0003728  
                                                            Sifra_sektor214%  
                                                                  -0.0169039  
                                                             Sifra_sektor23%  
                                                                  -0.6711506  
                                                             Sifra_sektor25%  
                                                                  -0.3120925  
                                                           Sifra_sektor26-9%  
                                                                  -0.1988994  
`Racio_pokrica_kamata_zaradom_pre_kamata_i_poreza_(Interest_Coverage_Ratio)`  
                                                                   0.0009682  
                                                             Broj_zaposlenih  
                                                                  -0.0021480  
                                                Racio_pokrica_obrtne_imovine  
                                                                   0.0114913  
                                                                   Velicina2  
                                                                  -0.1238959  
                                                                         T14  
                                                                   0.0104025  
                         Stopa_prinosa_na_sopstveni_kapital_pre_oporezivanja  
                                                                  -0.0013645  

Degrees of Freedom: 35913 Total (i.e. Null);  35891 Residual
Null Deviance:      14240 
Residual Deviance: 12580    AIC: 12630
model1.small <-glm(formula = default.y ~ T12 + Stopa_prinosa_na_ukupna_sredstva_pre_oporezivanja + 
    Asset_turnover + `Racio_novcane_likvidnosti_(Cash_ratio)` + 
    Sifra_opstine3 + udeo_u_kapitalu + Stepen_zaduzenosti + Vreme_kreditiranja_kupaca + 
    Sifra_sektor2 + `Racio_pokrica_kamata_zaradom_pre_kamata_i_poreza_(Interest_Coverage_Ratio)` + 
    Broj_zaposlenih + Racio_pokrica_obrtne_imovine + Velicina + 
    T14 + Stopa_prinosa_na_sopstveni_kapital_pre_oporezivanja, 
    family = binomial(link = "logit"), data = finalni_small)
  
model1.small.data.frame<-data.frame(fit1=model1.small$fitted.values, dif1=model1.small$model$default.y)
step(model.full.small,
     scope = list(lower=model.full.small,upper=model.null.small),
             direction="backward",
             data=finalni_small, trace=0)

Call:  glm(formula = default.y ~ `Racio_novcane_likvidnosti_(Cash_ratio)` + 
    Broj_zaposlenih + Stepen_zaduzenosti + `Racio_pokrica_kamata_zaradom_pre_kamata_i_poreza_(Interest_Coverage_Ratio)` + 
    Racio_pokrica_obrtne_imovine + Gotovinski_ciklus_1 + Vreme_kreditiranja_kupaca + 
    Vreme_naplate_potrazivanja + Vreme_placanja_dobavljacima + 
    Asset_turnover + Stopa_prinosa_na_sopstveni_kapital_pre_oporezivanja + 
    Stopa_prinosa_na_ukupna_sredstva_pre_oporezivanja + T12 + 
    T14 + udeo_u_kapitalu + Velicina + Sifra_sektor2 + Sifra_opstine3, 
    family = binomial(link = "logit"), data = finalni_small)

Coefficients:
                                                                 (Intercept)  
                                                                  -5.607e+00  
                                    `Racio_novcane_likvidnosti_(Cash_ratio)`  
                                                                  -1.659e+00  
                                                             Broj_zaposlenih  
                                                                  -2.205e-03  
                                                          Stepen_zaduzenosti  
                                                                   7.742e-03  
`Racio_pokrica_kamata_zaradom_pre_kamata_i_poreza_(Interest_Coverage_Ratio)`  
                                                                   9.621e-04  
                                                Racio_pokrica_obrtne_imovine  
                                                                   1.258e-02  
                                                         Gotovinski_ciklus_1  
                                                                  -7.728e-05  
                                                   Vreme_kreditiranja_kupaca  
                                                                   4.737e-04  
                                                  Vreme_naplate_potrazivanja  
                                                                  -8.573e-05  
                                                 Vreme_placanja_dobavljacima  
                                                                  -4.906e-06  
                                                              Asset_turnover  
                                                                  -1.883e-01  
                         Stopa_prinosa_na_sopstveni_kapital_pre_oporezivanja  
                                                                  -1.357e-03  
                           Stopa_prinosa_na_ukupna_sredstva_pre_oporezivanja  
                                                                  -2.888e-02  
                                                                         T12  
                                                                  -2.769e+00  
                                                                         T14  
                                                                   1.052e-02  
                                                             udeo_u_kapitalu  
                                                                   2.787e-02  
                                                                   Velicina2  
                                                                  -1.320e-01  
                                                            Sifra_sektor214%  
                                                                  -7.684e-03  
                                                             Sifra_sektor23%  
                                                                  -6.732e-01  
                                                             Sifra_sektor25%  
                                                                  -3.097e-01  
                                                           Sifra_sektor26-9%  
                                                                  -1.912e-01  
                                                            Sifra_opstine33%  
                                                                   3.658e-01  
                                                          Sifra_opstine34-5%  
                                                                   6.793e-01  
                                                            Sifra_opstine36%  
                                                                   9.400e-01  
                                                            Sifra_opstine37%  
                                                                   9.722e-01  
                                                           Sifra_opstine38>%  
                                                                   1.099e+00  

Degrees of Freedom: 35913 Total (i.e. Null);  35888 Residual
Null Deviance:      14240 
Residual Deviance: 12580    AIC: 12630
 model2.small=  glm(formula = default.y ~ `Racio_novcane_likvidnosti_(Cash_ratio)` + 
    Broj_zaposlenih + Stepen_zaduzenosti + `Racio_pokrica_kamata_zaradom_pre_kamata_i_poreza_(Interest_Coverage_Ratio)` + 
    Racio_pokrica_obrtne_imovine + Gotovinski_ciklus_1 + Vreme_kreditiranja_kupaca + 
    Vreme_naplate_potrazivanja + Vreme_placanja_dobavljacima + 
    Asset_turnover + Stopa_prinosa_na_sopstveni_kapital_pre_oporezivanja + 
    Stopa_prinosa_na_ukupna_sredstva_pre_oporezivanja + T12 + 
    T14 + udeo_u_kapitalu + Velicina + Sifra_sektor2 + Sifra_opstine3, 
    family = binomial(link = "logit"), data = finalni_small)
model2.small.data.frame=data.frame(fit2=model2.small$fitted.values, dif2=model2.small$model$default.y)

Wald statistik:

library(car)
Anova(model1.small, type="II", test="Wald")
Analysis of Deviance Table (Type II tests)

Response: default.y
                                                                             Df    Chisq
T12                                                                           1 214.3368
Stopa_prinosa_na_ukupna_sredstva_pre_oporezivanja                             1  44.5433
Asset_turnover                                                                1  45.5246
`Racio_novcane_likvidnosti_(Cash_ratio)`                                      1  68.2248
Sifra_opstine3                                                                5  52.3861
udeo_u_kapitalu                                                               1  62.2519
Stepen_zaduzenosti                                                            1  32.1689
Vreme_kreditiranja_kupaca                                                     1  14.0409
Sifra_sektor2                                                                 4  22.4703
`Racio_pokrica_kamata_zaradom_pre_kamata_i_poreza_(Interest_Coverage_Ratio)`  1  12.6258
Broj_zaposlenih                                                               1   4.8651
Racio_pokrica_obrtne_imovine                                                  1   4.1235
Velicina                                                                      1   4.3035
T14                                                                           1   2.7113
Stopa_prinosa_na_sopstveni_kapital_pre_oporezivanja                           1   2.5171
                                                                             Pr(>Chisq)    
T12                                                                           < 2.2e-16 ***
Stopa_prinosa_na_ukupna_sredstva_pre_oporezivanja                             2.488e-11 ***
Asset_turnover                                                                1.507e-11 ***
`Racio_novcane_likvidnosti_(Cash_ratio)`                                      < 2.2e-16 ***
Sifra_opstine3                                                                4.495e-10 ***
udeo_u_kapitalu                                                               3.022e-15 ***
Stepen_zaduzenosti                                                            1.413e-08 ***
Vreme_kreditiranja_kupaca                                                     0.0001789 ***
Sifra_sektor2                                                                 0.0001615 ***
`Racio_pokrica_kamata_zaradom_pre_kamata_i_poreza_(Interest_Coverage_Ratio)`  0.0003805 ***
Broj_zaposlenih                                                               0.0274049 *  
Racio_pokrica_obrtne_imovine                                                  0.0422917 *  
Velicina                                                                      0.0380345 *  
T14                                                                           0.0996418 .  
Stopa_prinosa_na_sopstveni_kapital_pre_oporezivanja                           0.1126168    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Langrange multiplier test:

anova(model1.small,
      model.null.small,
      test="Chisq")
Analysis of Deviance Table

Model 1: default.y ~ T12 + Stopa_prinosa_na_ukupna_sredstva_pre_oporezivanja + 
    Asset_turnover + `Racio_novcane_likvidnosti_(Cash_ratio)` + 
    Sifra_opstine3 + udeo_u_kapitalu + Stepen_zaduzenosti + Vreme_kreditiranja_kupaca + 
    Sifra_sektor2 + `Racio_pokrica_kamata_zaradom_pre_kamata_i_poreza_(Interest_Coverage_Ratio)` + 
    Broj_zaposlenih + Racio_pokrica_obrtne_imovine + Velicina + 
    T14 + Stopa_prinosa_na_sopstveni_kapital_pre_oporezivanja
Model 2: default.y ~ 1
  Resid. Df Resid. Dev  Df Deviance  Pr(>Chi)    
1     35891      12584                           
2     35913      14243 -22  -1659.5 < 2.2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Drugi nacin

 auroc.1<-auc(
      as.numeric(model1.small.data.frame$dif1),
      as.numeric(model1.small.data.frame$fit1))
 auroc.2<-auc(
      as.numeric(model2.small.data.frame$dif2),
      as.numeric(model2.small.data.frame$fit2))
 
 c(auroc.1,auroc.2)
[1] 0.7728342 0.7726643

validacioni uzorak

model1.small.pred<-as.numeric(predict(model1.small, newdata = finalni_small.test, type = "response"))
dif.small.valid<-small.test$default.y
model2.small.pred<-as.numeric(predict(model2.small, newdata = finalni_small.test, type = "response"))
auroc.1.pred<-auc(dif.small.valid, model1.small.pred)
auroc.2.pred<-auc(dif.small.valid, model2.small.pred)
c(auroc.1.pred,auroc.2.pred)
[1] 0.7467612 0.7469133
my.vars.small <-finalni_small# a matrix with your 14 different environmental variables
names(my.vars.small)[c(1, 4)] <-
  c("Racio_novcane_likvidnosti",
  "Racio_pokrica_kamata_zaradom_pre_kamata_i_poreza")
my.vars.small.valid <- finalni_small.test#
names(my.vars.small.valid)[c(1, 4)] <-
  c("Racio_novcane_likvidnosti",
  "Racio_pokrica_kamata_zaradom_pre_kamata_i_poreza")
my.vars.small$default.y=NULL
Adding new column 'default.y' then assigning NULL (deleting it).
library(speedglm)
nvar.small<-ncol(my.vars.small)
#colnames(my.vars) <- paste("var", 1:nvar, sep="") # add row names "var1" - "var14"
my.grad.data.small <- 1:nvar.small
sum.vars.small <- vector()
auc.p.small <- vector()
auc.pred.smal<-vector()
comb.mat.small <- matrix(numeric(0), nrow=nvar.small, ncol=0) # initialise the matrix containing all combinations
dif.small.valid<-small.test$default.y
for ( i in 1:nvar.small ) { # generate and store all possible combination of sums of the 14 variables
  
  t.mat.small <- combn(my.grad.data.small, m=i)
  
  comb.mat.small <- cbind(comb.mat.small, rbind(t.mat.small, matrix(NA, ncol=dim(t.mat.small)[2] , nrow=nvar.small-i)))
}
colnms.small<-colnames(my.vars.small)
my.vars.small$default.y=small.training$default.y
num.of.vars.small <- apply(as.data.frame(comb.mat.small),c(2)
                      , function(x) {
                      sum(as.numeric(!is.na(x)))
                      })
for ( j in 1:dim(comb.mat.small)[2] ) { # calculate and store the R2 for all combinations
  
  #sum.vec <- rowSums(my.vars[, comb.mat[, j]], na.rm=TRUE)
  sum.vars.small[j] <- paste( colnms.small[c(na.omit(comb.mat.small[, j]))], 
    collapse="+")
  relacija.small=as.formula(paste("default.y ~ ",sum.vars.small[j],sep = ""))
  model.small = speedglm(relacija.small,
                   data = my.vars.small,
                   y=TRUE,
                   fitted = TRUE,
                   family = binomial(link = "logit"))
  model.small.data.frame=data.frame(fit=fitted.values(model.small), dif=model.small$y)
  #browser()
  auc.p.small[j] <- auc_roc(as.numeric(model.small.data.frame$fit),as.numeric(model.small.data.frame$dif))
  #auc.p.small[j] <-fastAUC(as.numeric(model.small.data.frame$fit),as.numeric(model.small.data.frame$dif))
  
  
  model.small.pred<-as.numeric(predict(model.small, newdata = my.vars.small.valid, type = "response"))
  
  auc.pred.smal[j]<-auc_roc( model.small.pred,dif.small.valid)
  #auc.pred.smal[j]<-fastAUC( model.small.pred,dif.small.valid)
  
  if(j %in% round(seq(from=1, to=dim(comb.mat.small)[2],length.out = 100))) print(j/dim(comb.mat.small)[2])
  #print(j)
  #if(j==8) browser()
}
[1] 3.814712e-06
[1] 0.01010517
[1] 0.02020653
[1] 0.03030789
[1] 0.04040924
[1] 0.05050678
[1] 0.06060814
[1] 0.0707095
[1] 0.08081086
[1] 0.09091221
[1] 0.1010136
[1] 0.1111149
[1] 0.1212163
[1] 0.1313176
[1] 0.141419
[1] 0.1515165
[1] 0.1616179
[1] 0.1717193
[1] 0.1818206
[1] 0.191922
[1] 0.2020233
[1] 0.2121247
[1] 0.222226
[1] 0.2323274
[1] 0.2424288
[1] 0.2525263
[1] 0.2626276
[1] 0.272729
[1] 0.2828304
[1] 0.2929317
[1] 0.3030331
[1] 0.3131344
[1] 0.3232358
[1] 0.3333371
[1] 0.3434385
[1] 0.353536
[1] 0.3636374
[1] 0.3737388
[1] 0.3838401
[1] 0.3939415
[1] 0.4040428
[1] 0.4141442
[1] 0.4242455
[1] 0.4343469
[1] 0.4444483
[1] 0.4545458
[1] 0.4646472
[1] 0.4747485
[1] 0.4848499
[1] 0.4949512
[1] 0.5050526
[1] 0.5151539
[1] 0.5252553
[1] 0.5353567
[1] 0.545458
[1] 0.5555556
[1] 0.5656569
[1] 0.5757583
[1] 0.5858596
[1] 0.595961
[1] 0.6060623
[1] 0.6161637
[1] 0.6262651
[1] 0.6363664
[1] 0.6464678
[1] 0.6565653
[1] 0.6666667
[1] 0.676768
[1] 0.6868694
[1] 0.6969707
[1] 0.7070721
[1] 0.7171735
[1] 0.7272748
[1] 0.7373762
[1] 0.7474775
[1] 0.7575751
[1] 0.7676764
[1] 0.7777778
[1] 0.7878791
[1] 0.7979805
[1] 0.8080818
[1] 0.8181832
[1] 0.8282846
[1] 0.8383859
[1] 0.8484873
[1] 0.8585848
[1] 0.8686862
[1] 0.8787875
[1] 0.8888889
[1] 0.8989902
[1] 0.9090916
[1] 0.919193
[1] 0.9292943
[1] 0.9393957
[1] 0.949497
[1] 0.9595946
[1] 0.9696959
[1] 0.9797973
[1] 0.9898986
[1] 1
result.frame.small <- data.frame(combination=sum.vars.small, auc.p.small=auc.p.small, auc.valid.small=auc.pred.smal,num_of_vars=num.of.vars.small)
result.frame.small.sorted <- result.frame.small[order(auc.pred.smal, decreasing=TRUE), ]
head(result.frame.small.sorted, n=100) # the 10 "best" combinations

  1. Vidi Rating Models and Validation - Oesterreichische Nationalbank (OeNB).

  2. Hayden, E., & Porath, D. (2011). Statistical Methods to Develop Rating Models. In B. Engelmann, and R. Rauhmeier (Eds.), The Basel II Risk Parameters: Estimation, Validation, Stress Testing – with Applications to Loan Risk Management (pp. 1–12). New York: Springer.

LS0tDQp0aXRsZTogIlNrdXBsamFuamUgcG9kYXRha2EgemEgRVctTkJTIg0Kb3V0cHV0Og0KICBodG1sX25vdGVib29rOiANCiAgICB0b2M6IHllcw0KICBodG1sX2RvY3VtZW50OiBkZWZhdWx0DQotLS0NCg0KPGJvZHkgc3R5bGU9ImZvbnQtZmFtaWx5OnRpbWVzO3RleHQtYWxpZ246anVzdGlmeSIgPg0KDQo8aDMgc3R5bGU9ImNvbG9yOnJlZDsiPlVuaXZhcmlhdGUgYW5hbGl6YSBtYWxpaGloIHByZWR1emXEh2EgKG5hc3RhdmFrKTwvaDM+DQoNClBvdHJlYm5vIGplIHByZSBzdmVnYSByYXpkdm9qaXRpIHV6b3JhayBuYSB2YWxpZGFjaW9uaSBpIGVzdGltYWNpb25pLiBVIG5hY2VsdSBwcmF2aWxvIGplIGRhIHNlIHV6b3JhayBkZWxpIG5hIDcwOjMwIG5hIHN0cmFudSBlc3RpbWFjaWplLGkgdSBzbHVjYWp1IG1hbGloIHByZWR1emVjYSB0byBjZW1vIGkga29yaXN0aXRpLg0KUGEsIHBvY25pbW8uDQpgYGB7cn0NCiNpenJhY3VuYW0gYnJvaiByZWRvdmENCmJyb2oucmVkLnNtYWxsPC1ucm93KHNtYWxsKQ0KYnJvai5kaWZvbHRhLnNtYWxsPC1zdW0oYXMubnVtZXJpYyhzbWFsbCRkZWZhdWx0Lnk9PTEpKQ0KcHJvY2VuYXQuZGlmb2x0YTwtYnJvai5kaWZvbHRhLnNtYWxsL2Jyb2oucmVkLnNtYWxsDQpgYGANCg0KDQpgYGB7cn0NCnNldC5zZWVkKDQ1KQ0KI3pib2cgcmVwcm9kdWtjaWplDQpzYW1wbGUuc21hbGwgPC0NCnNhbXBsZShicm9qLnJlZC5zbWFsbCwgc2l6ZSA9IHJvdW5kKDAuNzUgKiBicm9qLnJlZC5zbWFsbCwgMCkpDQpzbWFsbC50cmFpbmluZyA8LSBzbWFsbFtzYW1wbGUuc21hbGwsIF0NCnNtYWxsLnRlc3QgPC0gc21hbGxbLXNhbXBsZS5zbWFsbCwgXQ0KYGBgDQoNCg0KIyMjIyoqVGVzdGlyYW5qZSByYWRuZSBoaXBvdGV6ZSwgZGlza3JpbWluYXRpdm5vc3RpLCBrb3JlbGFjaW9uZSBtYXRyaWNlKiogIA0KDQpKb3MgamVkbm9tIGNlbW8gcHJlZ2xlZGF0aSB2YXJpamFibGU6DQoNCmBgYHtyfQ0KI3JwaXZvdFRhYmxlKGxyZ2UudHJhaW5pbmcpDQpzdW1tYXJ5X3RhYmxlLnNtYWxsPC10KHNhcHBseShzbWFsbC50cmFpbmluZ1ssMTE6NDNdLG15LnN1bW1hcnksYXJnPVQpKQ0KdHJfc3VtbWFyeV90YWJsZS5zbWFsbDwtdChzdW1tYXJ5X3RhYmxlLnNtYWxsKQ0KDQpmb3JtYXRSb3VuZCgNCiAgICAgICAgICAgIGRhdGF0YWJsZSgNCiAgICAgICAgICAgICAgICAgICAgICBzdW1tYXJ5X3RhYmxlLnNtYWxsLGNhcHRpb24gPSAiVGFiZWxhIDMuOlN1bWFybmkgcHJpa2F6IiwNCiAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIgPSAnbm9uZScNCiAgICAgICAgICAgICAgICAgICAgICApLA0KICAgICAgICAgICAgY29sdW1ucyA9IGNvbG5hbWVzKHN1bW1hcnlfdGFibGUuc21hbGwpDQogICAgICAgICAgICkNCmBgYA0KDQpHZW5lcmFsbmEgcHJlcG9ydWthIGplIGRhIHNlIHJhZG5hIGhpcG90ZXphIHRlc3RpcmEgcHJlIHRyZXRtYW5hIG5lZG9zdGFqdcSHaWggdnJlZG5vc3RpIGJ1ZHXEh2kgZGEgxIdlIHNlIG5lZG9zdGFqdcSHZSB2cmVkbm9zdGkgcG9wdW5qYXZhdGkgdXNsb3ZubyBvZCBzdGFuamEgc29sdmVudG5vc3RpIGR1em5pa2EuIFNhbWltIHRpbSBvdmRlIGNlbW8ga2FvIHBydmkgdmlkIHNlbGVrY2lqZSBpc3BpdGF0aSByYWRudSBoaXBvdGV6dSBrYWtvIGtvbnRpbnVhbG5paCB0YWtvIGkga2F0ZWdvcmlja2loIHZhcmlqYWJsaS4gUG/EjWXEh2VtbyBzYSBrb250aW51YWxuaW1bXjNdIGkgYW5hbGl6dSByYWRpdGkgdSBwYXJ1IHNhIHByb3Zlcm9tIGRpc2tyaW1pbmF0aXZub3N0aSB2YXJpamFibGkuIEpvxaEgdSBUYWJlbGkgMyB2aWRpbW8gdmVsaWthIG9kc3R1cGFuamEgc3JlZG5qZSB2cmVkbm9zdGkgb2QgbWVkaWphbmUgaSB0cmltb3Zhbm9nIHByb3Nla2EsIGJ1ZHVjaSBkYSBqZSBwcm9zZWsga2FvIG1lcmEgY2VudHJhbG5lIHRlbmRlbmNpamUgb3NldGxqaXZhIG5hIGF1dGxhamVyZSBvZGx1Y3VqZW1vIHNlIGRhIHBvc21hdHJhbW8gbWVkaWphbnUgaSB0cmltb3ZhbiBwcm9zZWssIHNhbWltIHRpbSBtb2d1Y25vc3QgKnQgdGVzdGEqIG90cGFkYS4gRGFsamUsIHNsZWRlY2kgcHJlcG9ydWtlIGl6IGxpdGVyYXR1cmUgb3ZhaiBkZW8gYW5hbGl6ZSBvc2xvbml0aSBuYSBwb3NtYXRyYW5qZSBib3ggcGxvdG92YSBpIGJpY2UgZG9wdW5qZW4gZGlza3JpbWluYXRpdm5vbSBhbmFsaXpvbSBBVVJPQy1hLiBQcmkgdGVzdGlyYW5qdSBrb3JlbGFjaWphIHByYWcgc2VsZWtjaWplIHBvc3RhdmxqYW1vIG5hIDAuNSBpIG9kIGR2ZSBiaXJhbW8gb251IHZhcmlqYWJsdSBrb2phIGltYSB2ZWN1IGRpc2tyaW1pbmFjaW9udSBtb2MuIA0KDQpLb2Qga2F0ZWdvcmlja2loIHZhcmlqYWJsaSBwb3NtYXRyYWNlbW8gdGFiZWxlIGZyZWt2ZW5jaWphIHRhbW8gZ2RlIHRvIGJ1ZGUgaW1hbG8gc21pc2xhIGkgc3Byb3Zlc3RpIENoaS1zcXVhcmVkIHRlc3QuIE92b20gcHJpbGlrb20gcG90cmVibm8gamUgaSBwcmVncnVwaXNhdGkgb3ZlIHZhcmlqYWJsZSB0YWtvIGRhIGJ1ZHUgemFkb3ZvbGplbmkga3JpdGVyaWp1bWk6IA0KDQoqICAgYnJvaiAqZGlmb2x0YSogcG8ga2F0ZWdvcmlqaSBrYXRlZ29yaWNrZSB2YXJpamFibGUgbW9yYSBiaXRpIG1pbmltdW0gNQ0KKiAgIHVrdXBhbiBicm9qIGR1em5pa2EgcG8ga2F0ZWdvcmlqaSBrYXRlZ29yaWNrZSB2YXJpamFibGUgbW9yYSBiaXRpIHZlY2kgb2Qgc3RvDQoqICAgcHJhdmlsbyAxIHUgMTAsIHphIHN2YWtpaCAxMCBkaWZvbHRhIG1vxb5lbW8gZG9kYXRpIGplZG51IG9iamHFoW5qYXZhanXEh3UsIG92byBwcmF2aWxvIG5hbSBzbHV6aSBzYW1vIGthbyB2b2RpbGphDQoqICAgKmRlZmF1bHQgcmF0ZSogbW9yYSBiaXRpIHN0YXRpc3RpY2tpIHJhemxpY2l0IG9kICpkZWZhdWx0IHJhdGUqLWEgdWt1cG5vZyB1em9ya2EsIGluYWNlIHNlIHZyc2kgcHJlZ3J1cGFjaWphDQoqICAgaWFrbyBjZW1vIGlzcGl0YXRpIGhpcG90ZXp1IHNhZ2xlZGF2YW5qZW0gdGFiZWxhIGZyZWt2ZW5jaWphLCBwb3NsZWRuanUgcmVjIGNlIG5hbSBkYXRpIHNhbWkgbW9kZWwgaSBuamVnb3ZlICpwKiB2cmVkbm9zdGksIG9kbm9zbm8gKmxpa2VsaWhvb2QgcmF0aW8qIHRlc3QgICANCg0KUHJ2byBwcmVnbGVkYWptbyBzYW11IGRpc3RyaWJ1Y2lqdSBqb3MgamVkbm9tLCBtYWRhIHN1IG5la2Ugc3R2YXJpIHZlYyBqYXNuZSBpeiBUYWJlbGUgMyBoYWpkZSBpcGFrIGRhIHBvZ2xlZGFtby4gIA0KUHJ2byBrcmVpcmFtbyBmdW5rY2lqdSB6YSBwbG90aXJhbmplOiBxcSBwbG90YSwgYm94IHBsb3RhLCBwb3JlZGplbmphIGd1c3RpbmEgdmVyb3ZhdG5vY2UgKGtlcm5lbGEgZW1waXJpc2tpaCBkaXN0cmlidWNpamEgdmVyb3ZhdG5vY2UpIGkga29uYWNubyB6YSBwcm92ZXJ1IGRpc2tyaW1pbmFjaWplIFJPQyBrcml2ZS4NCmBgYHtyfQ0KI2RlbGltbyB1em9yYWsgbmEga29udGludWFsbmUgaSBrYXRlZ29yaWNrZQ0Kc21hbGwudHJhaW5pbmcuY29udGludWFsbmU8LXNtYWxsLnRyYWluaW5nWyxjKDcsNiwxMSwxMzo0MyldDQpzbWFsbC50cmFpbmluZy5rYXRlZ29yaWNrZTwtc21hbGwudHJhaW5pbmdbLGMoNyw4LDksMTAsMTIpXQ0KDQpzbWFsbC50ZXN0LmNvbnRpbnVhbG5lPC1zbWFsbC50ZXN0WyxjKDcsNiwxMSwxMzo0MyldDQpzbWFsbC50ZXN0LmthdGVnb3JpY2tlPC1zbWFsbC50ZXN0WyxjKDcsOCw5LDEwLDEyKV0NCg0KYGBgDQoNCiMjIyNLcmXEh2VtbyBzYSBvcGlzb20gc3Zha2UgdmFyaWphYmxlIHBvbmFvc29iOg0KIyNOZXByZWtpZG5lIHByb21lbmxqaXZlOg0KIyMjI1VkZW8gaXNwcmF2a2UgdSB1a3VwbmltIGtyZWRpdGltYSAgDQpfX19fX19fX19fX19fX19fX19fX19fDQoNCmBgYHtyLGZpZy53aWR0aD0xNixmaWcuaGVpZ2h0PTN9DQojZGVmaW5pc2VtIGZ1bmtjaWp1IHphIHBsb3RvdmFuamUNCg0KcGxvdGluZyhzbWFsbC50cmFpbmluZyw2LDcpDQoNCmBgYA0KDQoNCiogICBSYWRuYSBoaXBvdGV6YS1uaXNtbyBwb3N0YXZpbGkgcmFkbnUgaGlwb3RlenUgemEgb3Z1IHZhcmlqYWJsdQ0KKiAgIERpc2tyaW1pbmF0aXZub3N0IC0gcG9zdG9qaSBuYSA5NSUgc2lndXJub3N0aSANCiogICBhdXRsYWplcmkgLSBuYXJhdm5vIGltYSBpaCBpbWENCiogICBub3JtYWxub3N0IC0gbWEgZGEuLi4NCiANCiAgDQojIyMjQnJvaiB6YXBvc2xlbmloICANCl9fX19fX19fX19fXw0KYGBge3IsZmlnLndpZHRoPTE2LGZpZy5oZWlnaHQ9M30NCiNkZWZpbmlzZW0gZnVua2NpanUgemEgcGxvdG92YW5qZQ0KDQpwbG90aW5nKHNtYWxsLnRyYWluaW5nLDExLDcpDQoNCmBgYA0KKiAgIFJhZG5hIGhpcG90ZXphLW5pc21vIHBvc3RhdmlsaSByYWRudSBoaXBvdGV6dSB6YSBvdnUgdmFyaWphYmx1DQoqICAgRGlza3JpbWluYXRpdm5vc3QgLSBpbWEgamUgDQoqICAgYXV0bGFqZXJpIC0gbmFyYXZubyBpbWEgaWgNCiogICBub3JtYWxub3N0IC0gbWEgZGEuLi4NCg0KIyMjI1JpZ29yb3puaSByYWNpbyByZWR1a292YW5lIChtb25ldGFybmUpIGxpa3ZpZG5vc3RpICANCl9fX19fX19fX19fXw0KYGBge3IsZmlnLndpZHRoPTE2LGZpZy5oZWlnaHQ9M30NCiNkZWZpbmlzZW0gZnVua2NpanUgemEgcGxvdG92YW5qZQ0KDQpwbG90aW5nKHNtYWxsLnRyYWluaW5nLDEzLDcpDQoNCmBgYA0KKiAgIFJhZG5hIGhpcG90ZXphLXphZG92b2xqZW5hLCB2ZWNpIGRpZm9sdCBrb2QgbWFuamloIHZyZWRub3N0aQ0KKiAgIERpc2tyaW1pbmF0aXZub3N0IC0gaW1hIG5hIDk1JSB6bmFjYWpub3N0aSANCiogICBhdXRsYWplcmkgLSBuYXJhdm5vIGltYSBpaA0KKiAgIG5vcm1hbG5vc3QgLSBtYSBkYS4uLiAgDQoNCiMjIyNSYWNpbyBub3ZjYW5lIGxpa3ZpZG5vc3RpIChDYXNoX3JhdGlvKSAgDQpfX19fX19fX19fX19fXw0KYGBge3IsZmlnLndpZHRoPTE4LGZpZy5oZWlnaHQ9M30NCiNkZWZpbmlzZW0gZnVua2NpanUgemEgcGxvdG92YW5qZQ0KDQpwbG90aW5nKHNtYWxsLnRyYWluaW5nLDE0LDcpDQoNCmBgYA0KKiAgIFJhZG5hIGhpcG90ZXphLXphZG92b2xqZW5hLCB2ZWNpIGRpZm9sdCBrb2QgbWFuamloIHZyZWRub3N0aQ0KKiAgIERpc2tyaW1pbmF0aXZub3N0IC0gaW1hIG5hIDk1JSB6bmFjYWpub3N0aQ0KKiAgIGF1dGxhamVyaSAtIG5hcmF2bm8gaW1hIGloDQoqICAgbm9ybWFsbm9zdCAtIG1hIGRhLi4uICANCg0KIyMjI09wc3RpIHJhY2lvIGxpa3ZpZG5vc3RpICANCl9fX19fX19fX19fDQpgYGB7cixmaWcud2lkdGg9MTgsZmlnLmhlaWdodD0zfQ0KI2RlZmluaXNlbSBmdW5rY2lqdSB6YSBwbG90b3ZhbmplDQoNCnBsb3Rpbmcoc21hbGwudHJhaW5pbmcsMTUsNykNCg0KYGBgDQoqICAgUmFkbmEgaGlwb3RlemEtbmV6YWRvdm9samVuYSwgdmVjaSBkaWZvbHQga29kIHZlY2loIHZyZWRub3N0aQ0KKiAgIERpc2tyaW1pbmF0aXZub3N0IC0gaW1hIG5hIDk1JSB6bmFjYWpub3N0aSBhbGkgamUgbWFsYSwgdXppbWFjZW1vIHNhbW8gcHJla28gNTUlDQoqICAgYXV0bGFqZXJpIC0gbmFyYXZubyBpbWEgaWgNCiogICBub3JtYWxub3N0IC0gbWEgZGEuLi4gIA0KDQojIyMjU3RlcGVuX3phZHV6ZW5vc3RpICANCl9fX19fX19fX19fX19fX18NCmBgYHtyLGZpZy53aWR0aD0xOCxmaWcuaGVpZ2h0PTN9DQojZGVmaW5pc2VtIGZ1bmtjaWp1IHphIHBsb3RvdmFuamUNCg0KcGxvdGluZyhzbWFsbC50cmFpbmluZywxNiw3KQ0KDQpgYGANCg0KKiAgIFJhZG5hIGhpcG90ZXphLXphZG92b2xqZW5hLCB2ZWNpIGRpZm9sdCBrb2QgdmVjaWggdnJlZG5vc3RpDQoqICAgRGlza3JpbWluYXRpdm5vc3QgLSBpbWEgDQoqICAgYXV0bGFqZXJpIC0gbmFyYXZubyBpbWEgaWgNCiogICBub3JtYWxub3N0IC0gbWEgZGEuLi4NCg0KIyMjI0ludGVyZXN0IENvdmVyYWdlIFJhdGlvICANCl9fX19fX19fX19fX19fX19fDQpgYGB7cixmaWcud2lkdGg9MTgsZmlnLmhlaWdodD0zfQ0KI2RlZmluaXNlbSBmdW5rY2lqdSB6YSBwbG90b3ZhbmplDQoNCnBsb3Rpbmcoc21hbGwudHJhaW5pbmcsMTcsNykNCg0KYGBgDQoqICAgUmFkbmEgaGlwb3RlemEtemFkb3ZvbGplbmEsIHZlY2kgZGlmb2x0IGtvZCBtYW5qaWggdnJlZG5vc3RpDQoqICAgRGlza3JpbWluYXRpdm5vc3QgLSBpbWEgDQoqICAgYXV0bGFqZXJpIC0gbmFyYXZubyBpbWEgaWgNCiogICBub3JtYWxub3N0IC0gbWEgZGEsIGFsaSBiYXIgbGljaSBuYSBuZXN0byBub3JtYWxuby4uLg0KDQojIyMjUmFjaW8gcG9rcmljYSBvYnJ0bmUgaW1vdmluZSAgDQpfX19fX19fX19fX19fXw0KYGBge3IsZmlnLndpZHRoPTE4LGZpZy5oZWlnaHQ9M30NCiNkZWZpbmlzZW0gZnVua2NpanUgemEgcGxvdG92YW5qZQ0KDQpwbG90aW5nKHNtYWxsLnRyYWluaW5nLDE4LDcpDQoNCmBgYA0KKiAgIFJhZG5hIGhpcG90ZXphLXphZG92b2xqZW5hLCB2ZWNpIGRpZm9sdCBrb2QgbWFuamloIHZyZWRub3N0aQ0KKiAgIERpc2tyaW1pbmF0aXZub3N0IC0gaW1hDQoqICAgYXV0bGFqZXJpIC0gbmFyYXZubyBpbWEgaWgNCiogICBub3JtYWxub3N0IC0gbWEgZGEgDQoNCiMjIyNSYWNpbyBvYnJ0YSBwb3RyYXppdmFuamEgb2Qga3VwYWNhICANCl9fX19fX19fX19fX19fX18NCmBgYHtyLGZpZy53aWR0aD0xOCxmaWcuaGVpZ2h0PTN9DQojZGVmaW5pc2VtIGZ1bmtjaWp1IHphIHBsb3RvdmFuamUNCg0KcGxvdGluZyhzbWFsbC50cmFpbmluZywxOSw3KQ0KDQpgYGANCg0KKiAgIFJhZG5hIGhpcG90ZXphLXphZG92b2xqZW5hLCB2ZWNpIGRpZm9sdCBrb2QgbWFuamloIHZyZWRub3N0aQ0KKiAgIERpc2tyaW1pbmF0aXZub3N0IC0gaW1hDQoqICAgYXV0bGFqZXJpIC0gbmFyYXZubyBpbWEgaWgNCiogICBub3JtYWxub3N0IC0gbWEgZGEsIHZpc2Uga2FvICRcdGlsZGVcY2hpXjIkbm9zdCBoaWhpaGksIGthcGlyYXMgaGkga2FvIGhpIGRpc3RyaWJ1Y2lqYSA6KSAuLi4gDQoNCiMjIyNSYWNpbyBvYnJ0YSBwb3Nsb3ZuZSBpbW92aW5lICANCl9fX19fX19fX19fX19fX19fX18NCmBgYHtyLGZpZy53aWR0aD0xOCxmaWcuaGVpZ2h0PTN9DQojZGVmaW5pc2VtIGZ1bmtjaWp1IHphIHBsb3RvdmFuamUNCg0KcGxvdGluZyhzbWFsbC50cmFpbmluZywyMCw3KQ0KDQpgYGANCiogICBSYWRuYSBoaXBvdGV6YS16YWRvdm9samVuYSwgdmVjaSBkaWZvbHQga29kIG1hbmppaCB2cmVkbm9zdGkNCiogICBEaXNrcmltaW5hdGl2bm9zdCAtIGltYQ0KKiAgIGF1dGxhamVyaSAtIG5hcmF2bm8gaW1hIGloDQoqICAgbm9ybWFsbm9zdCAtIG1hIGRhLi4uDQoNCiMjIyNHb3Rvdmluc2tpIGNpa2x1cyAxICANCl9fX19fX19fX19fX19fX19fX19fX18NCmBgYHtyLGZpZy53aWR0aD0xOCxmaWcuaGVpZ2h0PTN9DQojZGVmaW5pc2VtIGZ1bmtjaWp1IHphIHBsb3RvdmFuamUNCg0KcGxvdGluZyhzbWFsbC50cmFpbmluZywyMSw3KQ0KDQpgYGANCiogICBSYWRuYSBoaXBvdGV6YS1uZXphZG92b2xqZW5hLCB2ZWNpIGRpZm9sdCBrb2QgbWFuamloIHZyZWRub3N0aQ0KKiAgIERpc2tyaW1pbmF0aXZub3N0IC0gaW1hIA0KKiAgIGF1dGxhamVyaSAtIG5hcmF2bm8gaW1hIGloDQoqICAgbm9ybWFsbm9zdCAtIG1hIGRhLi4uDQoNCiMjIyNWcmVtZSB2ZXppdmFuamEgemFsaWhhICANCl9fX19fX19fX19fX19fX19fX19fX19fDQpgYGB7cixmaWcud2lkdGg9MTgsZmlnLmhlaWdodD0zfQ0KI2RlZmluaXNlbSBmdW5rY2lqdSB6YSBwbG90b3ZhbmplDQoNCnBsb3Rpbmcoc21hbGwudHJhaW5pbmcsMjIsNykNCg0KYGBgDQoqICAgUmFkbmEgaGlwb3RlemEtemFkb3ZvbGplbmEsIHZlY2kgZGlmb2x0IGtvZCB2ZWNpaCB2cmVkbm9zdGkNCiogICBEaXNrcmltaW5hdGl2bm9zdCAtIGltYQ0KKiAgIGF1dGxhamVyaSAtIG5hcmF2bm8gaW1hIGloDQoqICAgbm9ybWFsbm9zdCAtIG1hIGRhLi4uDQoNCiMjIyNWcmVtZSBrcmVkaXRpcmFuamEga3VwYWNhICANCl9fX19fX19fX19fX19fX19fX19fX19fX19fX19fDQpgYGB7ciwgZmlnLndpZHRoPTE4LGZpZy5oZWlnaHQ9M30NCiNkZWZpbmlzZW0gZnVua2NpanUgemEgcGxvdG92YW5qZQ0KDQpwbG90aW5nKHNtYWxsLnRyYWluaW5nLDIzLDcpDQoNCmBgYA0KKiAgIFJhZG5hIGhpcG90ZXphLXphZG92b2xqZW5hLCB2ZWNpIGRpZm9sdCBrb2QgdmVjaWggdnJlZG5vc3RpDQoqICAgRGlza3JpbWluYXRpdm5vc3QgLSBpbWEgDQoqICAgYXV0bGFqZXJpIC0gbmFyYXZubyBpbWEgaWgNCiogICBub3JtYWxub3N0IC0gbWEgZGEuLi4NCg0KIyMjI1ZyZW1lIG5hcGxhdGUgcG90cmHFvml2YW5qYSAgDQpfX19fX19fX19fX19fX19fX18NCmBgYHtyLGZpZy53aWR0aD0xOCxmaWcuaGVpZ2h0PTN9DQojZGVmaW5pc2VtIGZ1bmtjaWp1IHphIHBsb3RvdmFuamUNCg0KcGxvdGluZyhzbWFsbC50cmFpbmluZywyNCw3KQ0KDQpgYGANCiogICBSYWRuYSBoaXBvdGV6YS16YWRvdm9samVuYSwgdmVjYSBzdG9wYSBkaWZvbHRhIGtvZCB2ZWNpaCB2cmVkbm9zdGkNCiogICBEaXNrcmltaW5hdGl2bm9zdCAtIGltYSANCiogICBhdXRsYWplcmkgLSBuYXJhdm5vIGltYSBpaA0KKiAgIG5vcm1hbG5vc3QgLSBtYSBkYS4uLg0KDQojIyMjVnJlbWUgcGxhxIdhbmphIGRvYmF2bGphxI1pbWEgIA0KX19fX19fX19fX19fX19fDQpgYGB7cixmaWcud2lkdGg9MTgsZmlnLmhlaWdodD0zfQ0KI2RlZmluaXNlbSBmdW5rY2lqdSB6YSBwbG90b3ZhbmplDQoNCnBsb3Rpbmcoc21hbGwudHJhaW5pbmcsMjUsNykNCg0KYGBgDQoqICAgUmFkbmEgaGlwb3RlemEtbmV6YWRvdm9samVuYSwgdmVjaSBkaWZvbHQga29kIG1hbmppaCB2cmVkbm9zdGksIGlwYWsgY2VtbyBqZSB1emV0aSwgamVyIG1vxb5lIGVrb25vbXNraSBkYSBzZSBvYmphc25pIHJlenVsdGF0DQoqICAgRGlza3JpbWluYXRpdm5vc3QgLSBpbWEgDQoqICAgYXV0bGFqZXJpIC0gbmFyYXZubyBpbWEgaWgNCiogICBub3JtYWxub3N0IC0gbWEgZGEuLi4NCg0KIyMjI0Fzc2V0IHR1cm5vdmVyDQpfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXw0KYGBge3IsZmlnLndpZHRoPTE4LGZpZy5oZWlnaHQ9M30NCiNkZWZpbmlzZW0gZnVua2NpanUgemEgcGxvdG92YW5qZQ0KDQpwbG90aW5nKHNtYWxsLnRyYWluaW5nLDI2LDcpDQoNCmBgYA0KDQoqICAgUmFkbmEgaGlwb3RlemEtemFkb3ZvbGplbmEsIHZlY2EgdmVyb3ZhdG5vY2EgZGlmb2x0YSBrb2QgbWFuamUgbWVkaWphbmUNCiogICBEaXNrcmltaW5hdGl2bm9zdCAtIGltYSANCiogICBhdXRsYWplcmkgLSBuYXJhdm5vIGltYSBpaA0KKiAgIG5vcm1hbG5vc3QgLSBtYSBkYS4uLg0KDQoNCiMjIyNSYXN0IEVCSVREQQ0KX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18NCmBgYHtyLGZpZy53aWR0aD0xOCxmaWcuaGVpZ2h0PTN9DQojZGVmaW5pc2VtIGZ1bmtjaWp1IHphIHBsb3RvdmFuamUNCg0KcGxvdGluZyhzbWFsbC50cmFpbmluZywyNyw3KQ0KDQpgYGANCiogICBSYWRuYSBoaXBvdGV6YS16YWRvdm9samVuYSwgdmVjYSB2ZXJvdmF0bm9jYSBkaWZvbHRhIGtvZCBtYW5qZSBtZWRpamFuZQ0KKiAgIERpc2tyaW1pbmF0aXZub3N0IC0gaW1hDQoqICAgYXV0bGFqZXJpIC0gbmFyYXZubyBpbWEgaWgNCiogICBub3JtYWxub3N0IC0gbWEgZGEuLi4NCg0KIyMjI1N0b3BhIHByaW5vc2EgbmEgc29wc3R2ZW5pIGthcGl0YWwgcHJlIG9wb3Jleml2YW5qYQ0KX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18NCmBgYHtyLGZpZy53aWR0aD0xOCxmaWcuaGVpZ2h0PTN9DQojZGVmaW5pc2VtIGZ1bmtjaWp1IHphIHBsb3RvdmFuamUNCg0KcGxvdGluZyhscmdlLnRyYWluaW5nLDI4LDcpDQoNCmBgYA0KDQoqICAgUmFkbmEgaGlwb3RlemEtbmUgem5hbSBrb2ppIG11IGplIGRqYXZvIGFsaSBldm8gb3ZkZSBjZW1vIG1lZGlqYW5hIHpkcmF2b2cgamUgYHIgbWVkaWFuKGFzLm1hdHJpeChzbWFsbC50cmFpbmluZ1tkZWZhdWx0Lnk9PTAsMjhdKSxuYS5ybT1UKWAgYSBuZXNvbHZlbnRub2cgamUgYHIgbWVkaWFuKGFzLm1hdHJpeChzbWFsbC50cmFpbmluZ1tkZWZhdWx0Lnk9PTEsMjhdKSxuYS5ybT1UKWAgc3RvIG9kZ292YXJhIHJhZG5vaiBoaXBvdGV6aSB2ZWNpIGRpZm9sdCBrb2QgbWFuamloIHZyZWRub3N0aQ0KKiAgIERpc2tyaW1pbmF0aXZub3N0IC0gaW1hDQoqICAgYXV0bGFqZXJpIC0gbmFyYXZubyBpbWEgaWgNCiogICBub3JtYWxub3N0IC0gbWEgZGEuLi4NCg0KIyMjI1N0b3BhIHByaW5vc2EgbmEgdWt1cG5hIHNyZWRzdHZhIHByZSBvcG9yZXppdmFuamENCl9fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fDQpgYGB7cixmaWcud2lkdGg9MTgsZmlnLmhlaWdodD0zfQ0KI2RlZmluaXNlbSBmdW5rY2lqdSB6YSBwbG90b3ZhbmplDQoNCnBsb3Rpbmcoc21hbGwudHJhaW5pbmcsMjksNykNCg0KYGBgDQoNCiogICBSYWRuYSBoaXBvdGV6YS1uZSB6bmFtIGtvamkgbXUgamUgZGphdm8gYWxpIGV2byBvdmRlIGNlbW8gbWVkaWphbmEgemRyYXZvZyBqZSBgciBtZWRpYW4oYXMubWF0cml4KGxyZ2UudHJhaW5pbmdbZGVmYXVsdC55PT0wLDI5XSksbmEucm09VClgIGEgbmVzb2x2ZW50bm9nIGplIGByIG1lZGlhbihhcy5tYXRyaXgobHJnZS50cmFpbmluZ1tkZWZhdWx0Lnk9PTEsMjldKSxuYS5ybT1UKWAgc3RvIG9kZ292YXJhIHJhZG5vaiBoaXBvdGV6aQ0KKiAgIERpc2tyaW1pbmF0aXZub3N0IC1pbWENCiogICBhdXRsYWplcmkgLSBuYXJhdm5vIGltYSBpaA0KKiAgIG5vcm1hbG5vc3QgLSBqZWRhbiBvZCBibGl6aWguLi4NCg0KIyMjI0Jhc2ljIEVhcm5pbmdzIFBvd2VyIFJhdGlvDQpfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXw0KYGBge3IsZmlnLndpZHRoPTE4LGZpZy5oZWlnaHQ9M30NCiNkZWZpbmlzZW0gZnVua2NpanUgemEgcGxvdG92YW5qZQ0KDQpwbG90aW5nKHNtYWxsLnRyYWluaW5nLDMwLDcpDQoNCmBgYA0KDQoqICAgUmFkbmEgaGlwb3RlemEtemFkb3ZvbGplbmEgamUsIHZlY2kgZGlmb2x0IHNhIG1hbmpvbSB2cmVkbm9zY3UNCiogICBEaXNrcmltaW5hdGl2bm9zdCAtIGltYSANCiogICBhdXRsYWplcmkgLSBuYXJhdm5vIGltYSBpaA0KKiAgIG5vcm1hbG5vc3QgLSBqb29rLi4uDQoNCiMjIyNSYXN0IHByaWhvZGEgb2QgcHJvZGFqZQ0KX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18NCmBgYHtyLGZpZy53aWR0aD0xOCxmaWcuaGVpZ2h0PTN9DQojZGVmaW5pc2VtIGZ1bmtjaWp1IHphIHBsb3RvdmFuamUNCg0KcGxvdGluZyhzbWFsbC50cmFpbmluZywzMSw3KQ0KDQpgYGANCg0KKiAgIFJhZG5hIGhpcG90ZXphLXphZG92b2xqZW5hIGplIHZlY2kgZGlmb2x0IGtvZCBtYW5qaWggdnJlZG5vc3RpDQoqICAgRGlza3JpbWluYXRpdm5vc3QgLSBpbWENCiogICBhdXRsYWplcmkgLSBuYXJhdm5vIGltYSBpaA0KKiAgIG5vcm1hbG5vc3QgLSBqb29rLi4uDQoNCiMjIyNQb2tyacSHZSBuZXRvIGthbWF0YQ0KX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18NCmBgYHtyLGZpZy53aWR0aD0xOCxmaWcuaGVpZ2h0PTN9DQojZGVmaW5pc2VtIGZ1bmtjaWp1IHphIHBsb3RvdmFuamUNCg0KcGxvdGluZyhzbWFsbC50cmFpbmluZywzMiw3KQ0KDQpgYGANCiogICBSYWRuYSBoaXBvdGV6YS16YWRvdm9samVuYSBqZSBtYW5qYSB2cmVkbm9zdCB2ZWNhIHZlcm92YXRub2NhIGRpZm9sdGENCiogICBEaXNrcmltaW5hdGl2bm9zdCAtIGltYQ0KKiAgIGF1dGxhamVyaSAtIG5hcmF2bm8gaW1hIGloDQoqICAgbm9ybWFsbm9zdCAtIGpvb2suLi4NCg0KIyMjI0NlbmEgdHXEkWloIGl6dm9yYSBzcmVkc3RhdmENCl9fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fDQpgYGB7cixmaWcud2lkdGg9MTgsZmlnLmhlaWdodD0zfQ0KI2RlZmluaXNlbSBmdW5rY2lqdSB6YSBwbG90b3ZhbmplDQoNCnBsb3RpbmcobHJnZS50cmFpbmluZywzMyw3LG49MSkNCg0KYGBgDQoqICAgUmFkbmEgaGlwb3RlemEtemFkb3ZvbGplbmEgamUgdmVjaSBkaWZvbHQga29kIHZlY2loIHZyZWRub3N0aQ0KKiAgIERpc2tyaW1pbmF0aXZub3N0IC0gaW1hDQoqICAgYXV0bGFqZXJpIC0gbmFyYXZubyBpbWEgaWgNCiogICBub3JtYWxub3N0IC0gam9vay4uLg0KDQoNCiMjIyNUMQ0KX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18NCmBgYHtyLGZpZy53aWR0aD0xOCxmaWcuaGVpZ2h0PTN9DQojZGVmaW5pc2VtIGZ1bmtjaWp1IHphIHBsb3RvdmFuamUNCg0KcGxvdGluZyhzbWFsbC50cmFpbmluZywzNCw3KQ0KDQpgYGANCiogICBSYWRuYSBoaXBvdGV6YS16YWRvdm9samVuYSBqZQ0KKiAgIERpc2tyaW1pbmF0aXZub3N0IC0gaW1hDQoqICAgYXV0bGFqZXJpIC0gbmFyYXZubyBpbWEgaWgNCiogICBub3JtYWxub3N0IC0gam9vay4uLg0KDQojIyMjVDINCl9fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fDQpgYGB7cixmaWcud2lkdGg9MTgsZmlnLmhlaWdodD0zfQ0KI2RlZmluaXNlbSBmdW5rY2lqdSB6YSBwbG90b3ZhbmplDQoNCnBsb3Rpbmcoc21hbGwudHJhaW5pbmcsMzUsNykNCg0KYGBgDQoNCiogICBSYWRuYSBoaXBvdGV6YS16YWRvdm9samVuYSBqZQ0KKiAgIERpc2tyaW1pbmF0aXZub3N0IC0gaW1hDQoqICAgYXV0bGFqZXJpIC0gbmFyYXZubyBpbWEgaWgNCiogICBub3JtYWxub3N0IC0gam9vay4uLg0KDQojIyMjVDMNCl9fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fDQpgYGB7cixmaWcud2lkdGg9MTgsZmlnLmhlaWdodD0zfQ0KI2RlZmluaXNlbSBmdW5rY2lqdSB6YSBwbG90b3ZhbmplDQoNCnBsb3Rpbmcoc21hbGwudHJhaW5pbmcsMzYsNykNCg0KYGBgDQoNCiogICBSYWRuYSBoaXBvdGV6YS16YWRvdm9samVuYSBqZQ0KKiAgIERpc2tyaW1pbmF0aXZub3N0IC0gaW1hDQoqICAgYXV0bGFqZXJpIC0gbmFyYXZubyBpbWEgaWgNCiogICBub3JtYWxub3N0IC0gam9vay4uLg0KDQoNCiMjIyNUNA0KX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18NCmBgYHtyLGZpZy53aWR0aD0xOCxmaWcuaGVpZ2h0PTN9DQojZGVmaW5pc2VtIGZ1bmtjaWp1IHphIHBsb3RvdmFuamUNCg0KcGxvdGluZyhzbWFsbC50cmFpbmluZywzNyw3KQ0KDQpgYGANCg0KDQoqICAgUmFkbmEgaGlwb3RlemEtemFkb3ZvbGplbmEgamUNCiogICBEaXNrcmltaW5hdGl2bm9zdCAtIG1hc3RlcnBpZWNlDQoqICAgYXV0bGFqZXJpIC0gbmFyYXZubyBpbWEgaWgNCiogICBub3JtYWxub3N0IC0gam9vay4uLg0KDQojIyMjVDUNCl9fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fDQpgYGB7cixmaWcud2lkdGg9MTgsZmlnLmhlaWdodD0zfQ0KI2RlZmluaXNlbSBmdW5rY2lqdSB6YSBwbG90b3ZhbmplDQoNCnBsb3Rpbmcoc21hbGwudHJhaW5pbmcsMzgsNykNCg0KYGBgDQoNCiogICBSYWRuYSBoaXBvdGV6YS16YWRvdm9samVuYSBqZQ0KKiAgIERpc2tyaW1pbmF0aXZub3N0IC0gaW1hDQoqICAgYXV0bGFqZXJpIC0gbmFyYXZubyBpbWEgaWgNCiogICBub3JtYWxub3N0IC0gam9vay4uLg0KDQojIyMjVDIxDQpfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXw0KYGBge3IsZmlnLndpZHRoPTE4LGZpZy5oZWlnaHQ9M30NCiNkZWZpbmlzZW0gZnVua2NpanUgemEgcGxvdG92YW5qZQ0KDQpwbG90aW5nKHNtYWxsLnRyYWluaW5nLDM5LDcpDQoNCmBgYA0KDQoNCiogICBSYWRuYSBoaXBvdGV6YS1uZXphZG92b2xqZW5hDQoqICAgRGlza3JpbWluYXRpdm5vc3QgLSBuZW1hLCB6YSBtYWxvDQoqICAgYXV0bGFqZXJpIC0gbmFyYXZubyBpbWEgaWgNCiogICBub3JtYWxub3N0IC0gam9vay4uLg0KDQojIyMjQWx0bWFuIFotc2NvcmUgMQ0KX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18NCmBgYHtyLGZpZy53aWR0aD0xOCxmaWcuaGVpZ2h0PTN9DQojZGVmaW5pc2VtIGZ1bmtjaWp1IHphIHBsb3RvdmFuamUNCg0KcGxvdGluZyhzbWFsbC50cmFpbmluZyw0MCw3KQ0KDQpgYGANCg0KKiAgIFJhZG5hIGhpcG90ZXphLXphZG92b2xqZW5hIGplDQoqICAgRGlza3JpbWluYXRpdm5vc3QgLSBtYXN0ZXJwaWVjZQ0KKiAgIGF1dGxhamVyaSAtIG5hcmF2bm8gaW1hIGloDQoqICAgbm9ybWFsbm9zdCAtIGpvb2suLi4gIA0KDQojIyMjQWx0bWFuIFotc2NvcmUgMg0KX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18NCmBgYHtyLGZpZy53aWR0aD0xOCxmaWcuaGVpZ2h0PTN9DQojZGVmaW5pc2VtIGZ1bmtjaWp1IHphIHBsb3RvdmFuamUNCg0KcGxvdGluZyhzbWFsbC50cmFpbmluZyw0MSw3KQ0KDQpgYGANCiogICBSYWRuYSBoaXBvdGV6YS16YWRvdm9samVuYSBqZQ0KKiAgIERpc2tyaW1pbmF0aXZub3N0IC0gaW1hDQoqICAgYXV0bGFqZXJpIC0gbmFyYXZubyBpbWEgaWgNCiogICBub3JtYWxub3N0IC0gam9vay4uLiAgDQoNCiMjIyNBbHRtYW4gWi1zY29yZSAzDQpfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXw0KYGBge3IsZmlnLndpZHRoPTE4LGZpZy5oZWlnaHQ9M30NCiNkZWZpbmlzZW0gZnVua2NpanUgemEgcGxvdG92YW5qZQ0KDQpwbG90aW5nKHNtYWxsLnRyYWluaW5nLDQyLDcpDQoNCmBgYA0KKiAgIFJhZG5hIGhpcG90ZXphLXphZG92b2xqZW5hIGplDQoqICAgRGlza3JpbWluYXRpdm5vc3QgLSBtYXN0ZXJwaWVjZQ0KKiAgIGF1dGxhamVyaSAtIG5hcmF2bm8gaW1hIGloDQoqICAgbm9ybWFsbm9zdCAtIGpvb2suLi4gIA0KDQoNCiMjIyNVZGVvIHUga2FwaXRhbHUgYmFua2UNCl9fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fDQpgYGB7cixmaWcud2lkdGg9MTgsZmlnLmhlaWdodD0zfQ0KI2RlZmluaXNlbSBmdW5rY2lqdSB6YSBwbG90b3ZhbmplDQoNCnBsb3Rpbmcoc21hbGwudHJhaW5pbmcsNDMsNykNCg0KYGBgDQoNCiogICBSYWRuYSBoaXBvdGV6YS16YWRvdm9samVuYSBqZSwgdmVjaSB1ZGVvIGxvc2lqaSBzdSB1IHByb3Nla3UNCiogICBEaXNrcmltaW5hdGl2bm9zdCAtIHphIHZlY2UgdnJlZG5vc3RpIGRhDQoqICAgYXV0bGFqZXJpIC0gbmFyYXZubyBpbWEgaWgNCiogICBub3JtYWxub3N0IC0gam9vay4uLiAgDQoNCl9fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18NCg0KDQojIyNLb3JlbGFjaW9uYSBtYXRyaWNhICANCg0KICANClUgdGFiZWxpIDUuIGlzcG9kIHZpZGltbyBkYSBuYWp2ZWN1IGRpc2tyaW1pbmFjaW9udSBtb2MgcG9zZWR1amUgdmFyaWphYmxhIFQxNCBvZG1haCBpemEga29qZSBqZSBBTHRtYW4gMS4gDQpgYGB7ciwgbWVzc2FnZT1GLCB3YXJuaW5nPUZ9DQojcHJvcmFjdW4NCmNvcj1jb3Ioc21hbGwudHJhaW5pbmcuY29udGludWFsbmVbLGMoLTEsLTMxLC0zMiwtMzMpXSwgdXNlID0gImNvbXBsZXRlLm9icyIpDQoNCiNkb2RhamVtbyBBVVJPQyBrYW8gZG9kYXRudSBrb2xvbnUgcG9yZWQgdmFyaWphYmxlDQoNCmNvcnJfc3VtbWFyeS5zbWFsbCA8LSBmdW5jdGlvbiAocHJlZGljdG9yKSB7DQogIHJlc3BvbnNlID0gZmFjdG9yKHNtYWxsLnRyYWluaW5nLmNvbnRpbnVhbG5lW1sxXV0pDQogIHN1cHByZXNzTWVzc2FnZXMoYXVjKHJlc3BvbnNlLCBhcy5udW1lcmljKHByZWRpY3RvcikpKQ0KfQ0KDQphdWNfc3VtYXJuby5zbWFsbDwtc2FwcGx5KHNtYWxsLnRyYWluaW5nLmNvbnRpbnVhbG5lWyxjKC0xLC0zMSwtMzIsLTMzKV0sIGNvcnJfc3VtbWFyeS5zbWFsbCkNCmtvcl9kaXNrci5zbWFsbDwtKGNiaW5kKGF1Y19zdW1hcm5vLnNtYWxsLGNvcikpIA0KDQpmb3JtYXRSb3VuZCgNCiAgICAgICAgICAgIGRhdGF0YWJsZSgNCiAgICAgICAgICAgICAgICAgICAgICBrb3JfZGlza3Iuc21hbGwsY2FwdGlvbiA9ICJUYWJlbGEgNS46U3VtYXJuaSBwcmlrYXoiLA0KICAgICAgICAgICAgICAgICAgICAgIGZpbHRlciA9ICdub25lJw0KICAgICAgICAgICAgICAgICAgICAgICksDQogICAgICAgICAgICBjb2x1bW5zID0gY29sbmFtZXMoa29yX2Rpc2tyLnNtYWxsKQ0KICAgICAgICAgICApDQphcy5kYXRhLmZyYW1lKGtvcl9kaXNrci5zbWFsbCkNCmBgYA0KDQpPdmRlIGtyZWlyYW0gZnVua2NpanUga29qYSBjZSBkYSBmaWx0cmlyYSB2YXJpamFibGUgcG8ga3JpdGVyaWp1bXUga29yZWxhY2lqZS4gTmFpbWUsIHBvIHVnbGVkdSBuYSBbXjRdIGthbyBrcml0ZXJpanVtIGdyYW5pY2Uga29lZmljaWplbnRhIGtvcmVsYWNpamUgcHJla28ga29qZSBuZSBiaXNtbyBzbWVsaSBwcmVsYXppdGkgdXplY2VtbyB2cmVkbm9zdCBvZCAwLjUga29qaSBjZSB1IHNwcmV6aSBzYSBBVVJPQyB2cmVkbm9zdGkgc2VsZWt0aXJhdGkgamVkbnUgb2QgZHZlIHZhcmlqYWJsZS4gS29uYWNhbiBpemJvciB2YXJpamFibGkgc2UgdmlkaSB1IGtvcmVsYWNpb25vaiB0YWJlbGkgaXNwb2QuICANCg0KYGBge3J9DQojYXNzdW1pbmcgdGhhdCB0YWJsZSBpcyBuIHggKG4rMSkgbWF0cml4IHdoZXJlIGZpcnN0IGNvbHVtbiBpcyBBVVJPQyB2YWx1ZSBhbmQgdGhlIHJlc3QgbiB4IG4gaXMgY29ycmVsYXRpb24gbWF0cml4IA0KDQoNCmNsZWFuX2Nvci5zbWFsbDwtY29ycl9lbGxpbWluYXRpb24oa29yX2Rpc2tyLnNtYWxsLHJvID0gKQ0Ka25pdHI6OmthYmxlKGNsZWFuX2Nvci5zbWFsbCwgY2FwdGlvbiA9ICJUYWJlbGEgNi4gc2tyYWNlbmEga29yZWxhY2lvbmEgdGFiZWxhIGtvamEgc2FkcnppIHZhcmlqYWJsZSBuYWQga29qaW1hIGNlIHNlIHZyc2l0aSBkYWxqYSBhbmFsaXphIikNCg0KYGBgDQoNCiMjI1RyZXRtYW4gcHJvYmxlbWF0aWNuaWggdmFyaWphYmxpICANCg0KT3Zha28sIGdlbmVyYWxubywgb25vIHN0byBuaXNtbyAobmlzbW8gaHRlbGkga29tZW50YXJpc2F0aSkga29tZW50YXJpc2FsaSBzdSBzaW1ldHJpY25vc3RpIHZhcmlqYWJsaS4gUG96aXRpdm5vIGFzaW1ldHJpY25vIGplIGJhciBwb2xhIHBvc21hdHJhbmloIHZhcmlqYWJsaSB0YWtvIGRhIGJpIHZhbGphbGEgbmVrYSB2cnN0YSBsb2dhcml0bW92YW5lIHRyYW5zZm9ybWFjaWplIHV6IHZvZGplbmplIHJhY3VuYSBvIG5lZ2F0aXZuaW0gdnJlZG5vc3RpbWEgKG5hIHByaW1lciB0cmFuc2Zvcm1hY2lqYSB0aXBhOg0KJFxsb2codmFyICsgXG1pbih2YXIpICsgMSkpJCBiaSBzZSBwb2JyaW51bGEgemEgbmVnYXRpdm5lIHZyZWRub3N0aS4gQm94DQpaYSBuZWdhdGl2bnUgYXNpbWV0cmljbm9zdCBiaSBrb3Jpc3RpbGkgZXZlbnR1YWxubyBla3Nwb25lbmNpamFsbnUgdHJhbnNmb3JtYWNpanUuIFZpZGVjZW1vIHBvc2xlIHBydm9nIHN0ZXB3aXNlYSBpIEFVUk9DLWEuICANCg0KSXBhaywgb3ZkZSBjZW1vIHNlIGtvbmNlbnRyaXNhdGkgbmEgcGFyIHByZXRob2RubyBuYXBvbWVudXRpaCB2YXJpamFibGkuICANCg0KIyMjI1Bva3JpxIdlIG5ldG8ga2FtYXRhICANClBydm8gY2VtbyBwb2RlbGl0aSB2YXJpamFibHUgbmEgbiBpbnRlcnZhbGEuIFphIG9wdGltYWxhbiBicm9qIGludGVydmFsYSBtb3plbW8gaXNrb3Jpc3RpdGkgZHJ1Z3UgZnVua2NpanUga29qYSBpbWEgYWxnb3JpdGFtIGtvamkgYmlyYSBicm9qIGludGVydmFsYSBvZCAxMCBkbyAyMCBuYSBvc25vdnUgb2RyZWRqZW5paCBrcml0ZXJpanVtYSwgdmlkaSBoZWxwIGZ1bmtjaWplIGRvbGUuDQoNCmBgYHtyfQ0KI2tyZWlyYW0gdGFiZWx1IG9kIHBva3JpY2EgbmV0byBrYW1hdGEgaSBpbmRpa2F0b3JhIGRlZmF1bHQtYQ0KZGF0YTwtc21hbGwudHJhaW5pbmdbLGMoImRlZmF1bHQueSIsIlBva3JpY2VfbmV0b19rYW1hdGEiKV0NCg0KSVYgPC0gY3JlYXRlX2luZm90YWJsZXMoZGF0YT1kYXRhLA0KICAgICAgICAgICAgICAgICAgICAgICAgeT0iZGVmYXVsdC55IiwgDQogICAgICAgICAgICAgICAgICAgICAgICBwYXJhbGxlbD1GQUxTRSkNCklWX1ZhbHVlID0gZGF0YS5mcmFtZShJViRTdW1tYXJ5KQ0KSVZfVmFsdWUNCklWJFRhYmxlcw0KcGxvdF9pbmZvdGFibGVzKElWLCJQb2tyaWNlX25ldG9fa2FtYXRhIikNCmBgYA0KRGFrbGUgb3B0aW11bSBqZSAxMCwgaW1hanVjaSB1IG9iemlyIG5lZG9zdGFqdWNlIHZyZWRub3N0aSBrYW8gMTEga2F0ZWdvcmlqdS4gU2FkYSByYWN1bmFtbyBmaXRpbmcgZnVua2NpanUgdHJhbnNmb3JtYWNpamUuIEdlbmVyYWxubywgbW9nbGkgYmlzbW8gcG9kZWxpdGkgdmFyaWphYmx1IHUgOCBrYXRlZ29yaWNraWgsIGFsaSBqYSBiaWggaXpiZWdhbyB0by4gSGFqZGUgcHJ2byBkYSB2aWRpbW8gZW1waXJpanNrdSBkaXN0cmlidWNpanUsIHBhIGRhIGZpdHVqZW1vLg0KYGBge3J9DQoNCiNpenJhY3VuYW0gbWVkaWphbnUgcG8gc3Zha29tIGJpbnUNCg0KDQoNCg0KYGBgDQoNCg0KDQojI0thdGVnb3JpY2tlIHByb21lbmxqaXZlOiAgDQoNClBvc3RvamUgdHJpIGthdGVnb3JpY2tlIHZhcmlqYWJsZSBrb2plIGplIHBvdHJlYm5vIGFuYWxpemlyYXRpOiAgDQoNCiogICBTaWZyYSBvcHN0aW5lLWdlbmVyYWxubyB2ZWxpa2kgYnJvaiBvcHN0aW5hIGNlIHByYXZpdGkgcHJvYmxlbSwgcHJlcG9ydWthIGplIGRhIHNlIHBvdGVuY2lqYWxubyBpenZyc2kgcG9kZWxhIG5hIEJlb2dyYWQgaSBvc3RhdGFrIFNyYmlqZSwgaWxpLCBuYSB2ZWxpa2UgZ3JhZG92ZSBpIG1hbGUgb3BzdGluZSwgZ2RlIGJpIHUgdmVsaWtlIGdyYWRvdmUgdXNsaSBCZW9ncmFkLCBOaXMsIE5vdmkgU2FkLCBpIG5hIGtyYWp1IGNlbW8gcG9rdXNhdGkgZGEgdXBvdHJlYmltbyBla29ub21za3UgcmF6dmlqZW5vc3Qgb3BzdGluYSBrYW8gcG9rYXphdGVsai4gT25hIHNlIG1lbmphIHN2YWtlIGdvZGluZSwgYWxpIGtvc3R1ciBvc3RhamUgc2xpY2FuLCBwYSBiaXNtbyB1IG92b20gZGVsdSByYXp2aWphbmphIG1vZGVsYSB1emVsaSB2cmVkbm9zdCBpeiAyMDE0LiBnb2RpbmUsIGEgdWtvbGlrbyBzZSBpc3Bvc3Rhdmkga2FvIGJpdGFuIGZha3RvciBtb3plbW8gemF0cmF6aXRpIHNlcmlqdSwga29qYSwgbWVkanV0aW0gbmUgaWRlIHByZSAyMDEwLiBnb2RpbmUuDQoqICAgU2lmcmEgc2VrdG9yYS1nZW5lcmFsbm8sIG5lIHBvc3Rvamkgb3BzdGUgbWlzbGplbmplIG8gb3ZvaiB2YXJpamFibGksIG5pdGkgb3ByYXZkYW5vc3QgemFzdG8gYmkgb25hIHVzbGEgdSBvYnJhY3VuLCBzdG9qaSBkYSBqZSBicm9qIGRpZm9sdGEgcG8gc2VrdG9yaW1hIHJhemxpY2l0LCBhbGkgbmVraSBzZWt0b3JpIGltYWp1IHZybG8gbWFsaSBicm9qIG9ic2VydmFjaWphLCB0YWtvIGRhIGNlbW8gbW9yYXRpIHByZWdydXBpc2F0aSB2YXJpamFibGUgbmEgbmFqdmVjZSBzZWt0b3JlIGkgb3N0YWxlLCB6YXZpc25vIG9kIHZlYyBuYXZlZGVuaWgga3JpdGVyaWp1bWEgdSBwb2NldGt1IG92b2cgcG9nbGF2bGphLiAgDQoqICAgU3RyYW5pIGludmVzdGl0b3Itc2l0dWFjaWphIGplIGphc25hICANCg0KYGBge3J9DQpycGl2b3RUYWJsZShscmdlLnRyYWluaW5nLmthdGVnb3JpY2tlLA0KICAgICAgICAgICAgcm93cyA9ICJkZWZhdWx0LnkiLCANCiAgICAgICAgICAgIGNvbHMgPSAiU3RyYW5pX2ludmVzdGl0b3IiLA0KICAgICAgICAgICAgYWdncmVnYXRvck5hbWUgPSAiQ291bnQgYXMgRnJhY3Rpb24gb2YgQ29sdW1ucyIpDQpgYGANCg0KDQoNCiMjIyNTaWZyYSBzZWt0b3JhOiAgDQoNCg0KYGBge3J9DQpmcmVxX3RhYmxlPWZ1bmN0aW9uKGR0YSxrYXRlZ29yaWNhbCxkZWZhdWx0KXsNCiAga2F0ZWdvcmljYWw9YXMubmFtZShrYXRlZ29yaWNhbCkNCiAgZGVmYXVsdD1hcy5uYW1lKGRlZmF1bHQpDQogIHRtcD1kdGFbLC5OLGJ5PS4oZXZhbChrYXRlZ29yaWNhbCksZXZhbChkZWZhdWx0KSldDQogIGZyZWt2ZW5jYV9zZWt0b3I8LWRjYXN0KHRtcCxldmFsKGthdGVnb3JpY2FsKX5ldmFsKGRlZmF1bHQpLHZhbHVlLnZhcj0iTiIpDQogIGZyZWt2ZW5jYV9zZWt0b3IkYDBgW2lzLm5hKGZyZWt2ZW5jYV9zZWt0b3IkYDBgKV09MA0KICBmcmVrdmVuY2Ffc2VrdG9yJGAxYFtpcy5uYShmcmVrdmVuY2Ffc2VrdG9yJGAxYCldPTANCiAgdWt1cG5vPC1mcmVrdmVuY2Ffc2VrdG9yJGAwYCtmcmVrdmVuY2Ffc2VrdG9yJGAxYA0KICBmcmVrdmVuY2Ffc2VrdG9yPC1jYmluZC5kYXRhLmZyYW1lKGZyZWt2ZW5jYV9zZWt0b3IsdWt1cG5vKQ0KICBmcmVrdmVuY2Ffc2VrdG9yWyxkZWZhdWx0X3JhdGU6PWZyZWt2ZW5jYV9zZWt0b3IkYDFgL3VrdXBub10NCiAgYXMuZGF0YS5mcmFtZShmcmVrdmVuY2Ffc2VrdG9yKQ0KfQ0KDQpmcmVxX3RhYmxlKHNtYWxsLnRyYWluaW5nLmthdGVnb3JpY2tlLCJTaWZyYV9zZWt0b3IiLCJkZWZhdWx0LnkiKQ0KYGBgDQoNCiANCmBgYHtyfQ0Kc21hbGwudHJhaW5pbmcua2F0ZWdvcmlja2UkU2lmcmFfc2VrdG9yMVtzbWFsbC50cmFpbmluZy5rYXRlZ29yaWNrZSRTaWZyYV9zZWt0b3I9PSJCIl08LSI0JSINCnNtYWxsLnRyYWluaW5nLmthdGVnb3JpY2tlJFNpZnJhX3Nla3RvcjFbc21hbGwudHJhaW5pbmcua2F0ZWdvcmlja2UkU2lmcmFfc2VrdG9yPT0iRyJdPC0iNCUiDQpzbWFsbC50cmFpbmluZy5rYXRlZ29yaWNrZSRTaWZyYV9zZWt0b3IxW3NtYWxsLnRyYWluaW5nLmthdGVnb3JpY2tlJFNpZnJhX3Nla3Rvcj09IkoiXTwtIjQlIg0Kc21hbGwudHJhaW5pbmcua2F0ZWdvcmlja2UkU2lmcmFfc2VrdG9yMVtzbWFsbC50cmFpbmluZy5rYXRlZ29yaWNrZSRTaWZyYV9zZWt0b3I9PSJQIl08LSI0JSINCnNtYWxsLnRyYWluaW5nLmthdGVnb3JpY2tlJFNpZnJhX3Nla3RvcjFbc21hbGwudHJhaW5pbmcua2F0ZWdvcmlja2UkU2lmcmFfc2VrdG9yPT0iUSJdPC0iNCUiDQpzbWFsbC50cmFpbmluZy5rYXRlZ29yaWNrZSRTaWZyYV9zZWt0b3IxW3NtYWxsLnRyYWluaW5nLmthdGVnb3JpY2tlJFNpZnJhX3Nla3Rvcj09IlIiXTwtIjQlIg0Kc21hbGwudGVzdC5rYXRlZ29yaWNrZSRTaWZyYV9zZWt0b3IxW3NtYWxsLnRlc3Qua2F0ZWdvcmlja2UkU2lmcmFfc2VrdG9yPT0iQiJdPC0iNCUiDQpzbWFsbC50ZXN0LmthdGVnb3JpY2tlJFNpZnJhX3Nla3RvcjFbc21hbGwudGVzdC5rYXRlZ29yaWNrZSRTaWZyYV9zZWt0b3I9PSJHIl08LSI0JSINCnNtYWxsLnRlc3Qua2F0ZWdvcmlja2UkU2lmcmFfc2VrdG9yMVtzbWFsbC50ZXN0LmthdGVnb3JpY2tlJFNpZnJhX3Nla3Rvcj09IkoiXTwtIjQlIg0Kc21hbGwudGVzdC5rYXRlZ29yaWNrZSRTaWZyYV9zZWt0b3IxW3NtYWxsLnRlc3Qua2F0ZWdvcmlja2UkU2lmcmFfc2VrdG9yPT0iUCJdPC0iNCUiDQpzbWFsbC50ZXN0LmthdGVnb3JpY2tlJFNpZnJhX3Nla3RvcjFbc21hbGwudGVzdC5rYXRlZ29yaWNrZSRTaWZyYV9zZWt0b3I9PSJRIl08LSI0JSINCnNtYWxsLnRlc3Qua2F0ZWdvcmlja2UkU2lmcmFfc2VrdG9yMVtzbWFsbC50ZXN0LmthdGVnb3JpY2tlJFNpZnJhX3Nla3Rvcj09IlIiXTwtIjQlIg0KDQpzbWFsbC50cmFpbmluZy5rYXRlZ29yaWNrZSRTaWZyYV9zZWt0b3IxW3NtYWxsLnRyYWluaW5nLmthdGVnb3JpY2tlJFNpZnJhX3Nla3Rvcj09Ik0iXTwtIjYlIg0Kc21hbGwudHJhaW5pbmcua2F0ZWdvcmlja2UkU2lmcmFfc2VrdG9yMVtzbWFsbC50cmFpbmluZy5rYXRlZ29yaWNrZSRTaWZyYV9zZWt0b3I9PSJOIl08LSI2JSINCnNtYWxsLnRyYWluaW5nLmthdGVnb3JpY2tlJFNpZnJhX3Nla3RvcjFbc21hbGwudHJhaW5pbmcua2F0ZWdvcmlja2UkU2lmcmFfc2VrdG9yPT0iUyJdPC0iNiUiDQpzbWFsbC50cmFpbmluZy5rYXRlZ29yaWNrZSRTaWZyYV9zZWt0b3IxW3NtYWxsLnRyYWluaW5nLmthdGVnb3JpY2tlJFNpZnJhX3Nla3Rvcj09IkYiXTwtIjYlIg0Kc21hbGwudGVzdC5rYXRlZ29yaWNrZSRTaWZyYV9zZWt0b3IxW3NtYWxsLnRlc3Qua2F0ZWdvcmlja2UkU2lmcmFfc2VrdG9yPT0iTSJdPC0iNiUiDQpzbWFsbC50ZXN0LmthdGVnb3JpY2tlJFNpZnJhX3Nla3RvcjFbc21hbGwudGVzdC5rYXRlZ29yaWNrZSRTaWZyYV9zZWt0b3I9PSJOIl08LSI2JSINCnNtYWxsLnRlc3Qua2F0ZWdvcmlja2UkU2lmcmFfc2VrdG9yMVtzbWFsbC50ZXN0LmthdGVnb3JpY2tlJFNpZnJhX3Nla3Rvcj09IlMiXTwtIjYlIg0Kc21hbGwudGVzdC5rYXRlZ29yaWNrZSRTaWZyYV9zZWt0b3IxW3NtYWxsLnRlc3Qua2F0ZWdvcmlja2UkU2lmcmFfc2VrdG9yPT0iRiJdPC0iNiUiDQoNCnNtYWxsLnRyYWluaW5nLmthdGVnb3JpY2tlJFNpZnJhX3Nla3RvcjFbc21hbGwudHJhaW5pbmcua2F0ZWdvcmlja2UkU2lmcmFfc2VrdG9yPT0iSCJdPC0iMyUiDQpzbWFsbC50cmFpbmluZy5rYXRlZ29yaWNrZSRTaWZyYV9zZWt0b3IxW3NtYWxsLnRyYWluaW5nLmthdGVnb3JpY2tlJFNpZnJhX3Nla3Rvcj09IkUiXTwtIjMlIg0Kc21hbGwudGVzdC5rYXRlZ29yaWNrZSRTaWZyYV9zZWt0b3IxW3NtYWxsLnRlc3Qua2F0ZWdvcmlja2UkU2lmcmFfc2VrdG9yPT0iSCJdPC0iMyUiDQpzbWFsbC50ZXN0LmthdGVnb3JpY2tlJFNpZnJhX3Nla3RvcjFbc21hbGwudGVzdC5rYXRlZ29yaWNrZSRTaWZyYV9zZWt0b3I9PSJFIl08LSIzJSINCg0Kc21hbGwudHJhaW5pbmcua2F0ZWdvcmlja2UkU2lmcmFfc2VrdG9yMVtzbWFsbC50cmFpbmluZy5rYXRlZ29yaWNrZSRTaWZyYV9zZWt0b3I9PSJJIl08LSIxMCUiDQpzbWFsbC50cmFpbmluZy5rYXRlZ29yaWNrZSRTaWZyYV9zZWt0b3IxW3NtYWxsLnRyYWluaW5nLmthdGVnb3JpY2tlJFNpZnJhX3Nla3Rvcj09IkoiXTwtIjklIg0Kc21hbGwudHJhaW5pbmcua2F0ZWdvcmlja2UkU2lmcmFfc2VrdG9yMVtzbWFsbC50cmFpbmluZy5rYXRlZ29yaWNrZSRTaWZyYV9zZWt0b3I9PSJLIl08LSI5JSINCnNtYWxsLnRlc3Qua2F0ZWdvcmlja2UkU2lmcmFfc2VrdG9yMVtzbWFsbC50ZXN0LmthdGVnb3JpY2tlJFNpZnJhX3Nla3Rvcj09IkkiXTwtIjEwJSINCnNtYWxsLnRlc3Qua2F0ZWdvcmlja2UkU2lmcmFfc2VrdG9yMVtzbWFsbC50ZXN0LmthdGVnb3JpY2tlJFNpZnJhX3Nla3Rvcj09IkoiXTwtIjklIg0Kc21hbGwudGVzdC5rYXRlZ29yaWNrZSRTaWZyYV9zZWt0b3IxW3NtYWxsLnRlc3Qua2F0ZWdvcmlja2UkU2lmcmFfc2VrdG9yPT0iSyJdPC0iOSUiDQoNCnNtYWxsLnRyYWluaW5nLmthdGVnb3JpY2tlJFNpZnJhX3Nla3RvcjFbc21hbGwudHJhaW5pbmcua2F0ZWdvcmlja2UkU2lmcmFfc2VrdG9yPT0iQSJdPC0iNSUiDQpzbWFsbC50cmFpbmluZy5rYXRlZ29yaWNrZSRTaWZyYV9zZWt0b3IxW3NtYWxsLnRyYWluaW5nLmthdGVnb3JpY2tlJFNpZnJhX3Nla3Rvcj09IkMiXTwtIjUlIg0Kc21hbGwudHJhaW5pbmcua2F0ZWdvcmlja2UkU2lmcmFfc2VrdG9yMVtzbWFsbC50cmFpbmluZy5rYXRlZ29yaWNrZSRTaWZyYV9zZWt0b3I9PSJEIl08LSI1JSINCnNtYWxsLnRlc3Qua2F0ZWdvcmlja2UkU2lmcmFfc2VrdG9yMVtzbWFsbC50ZXN0LmthdGVnb3JpY2tlJFNpZnJhX3Nla3Rvcj09IkEiXTwtIjUlIg0Kc21hbGwudGVzdC5rYXRlZ29yaWNrZSRTaWZyYV9zZWt0b3IxW3NtYWxsLnRlc3Qua2F0ZWdvcmlja2UkU2lmcmFfc2VrdG9yPT0iQyJdPC0iNSUiDQpzbWFsbC50ZXN0LmthdGVnb3JpY2tlJFNpZnJhX3Nla3RvcjFbc21hbGwudGVzdC5rYXRlZ29yaWNrZSRTaWZyYV9zZWt0b3I9PSJEIl08LSI1JSINCg0Kc21hbGwudHJhaW5pbmcua2F0ZWdvcmlja2UkU2lmcmFfc2VrdG9yMVtzbWFsbC50cmFpbmluZy5rYXRlZ29yaWNrZSRTaWZyYV9zZWt0b3I9PSJMIl08LSIxNCUiDQpzbWFsbC50ZXN0LmthdGVnb3JpY2tlJFNpZnJhX3Nla3RvcjFbc21hbGwudGVzdC5rYXRlZ29yaWNrZSRTaWZyYV9zZWt0b3I9PSJMIl08LSIxNCUiDQoNCmZyZXFfdGFibGUoc21hbGwudHJhaW5pbmcua2F0ZWdvcmlja2UsIlNpZnJhX3Nla3RvcjEiLCJkZWZhdWx0LnkiKQ0KYGBgDQoNCmBgYHtyfQ0KDQpkYXRhX3NpZnJhX3Nla3Rvci5zbWFsbDwtc21hbGwudHJhaW5pbmcua2F0ZWdvcmlja2VbLGMoImRlZmF1bHQueSIsIlNpZnJhX3Nla3RvcjEiKV0NCg0KSVZfc2lmcmFfc2VrdG9yLnNtYWxsPC1jcmVhdGVfaW5mb3RhYmxlcyhkYXRhPWRhdGFfc2lmcmFfc2VrdG9yLnNtYWxsLA0KICAgICAgICAgICAgICAgICAgICAgICAgeT0iZGVmYXVsdC55IiwgDQogICAgICAgICAgICAgICAgICAgICAgICBwYXJhbGxlbD1GQUxTRSkNCg0KSVZfc2lmcmFfc2VrdG9yLnNtYWxsJFRhYmxlcw0KDQoNCg0KYGBgDQoqSW5mb3JtYXRpb24gdmFsdWUqIGplIGJ6dmV6ZSwgcHJvYmFqbW8gc2FkYSBqb3MgZGEgcHJlZ3J1cGnFoWVtbzoNCmBgYHtyfQ0KDQpzbWFsbC50cmFpbmluZy5rYXRlZ29yaWNrZSRTaWZyYV9zZWt0b3IyW3NtYWxsLnRyYWluaW5nLmthdGVnb3JpY2tlJFNpZnJhX3Nla3RvcjE9PSIxMCUiXTwtIjEwJSINCnNtYWxsLnRyYWluaW5nLmthdGVnb3JpY2tlJFNpZnJhX3Nla3RvcjJbc21hbGwudHJhaW5pbmcua2F0ZWdvcmlja2UkU2lmcmFfc2VrdG9yMT09IjE0JSJdPC0iMTQlIg0Kc21hbGwudHJhaW5pbmcua2F0ZWdvcmlja2UkU2lmcmFfc2VrdG9yMltzbWFsbC50cmFpbmluZy5rYXRlZ29yaWNrZSRTaWZyYV9zZWt0b3IxPT0iOSUiXTwtIjYtOSUiDQpzbWFsbC50cmFpbmluZy5rYXRlZ29yaWNrZSRTaWZyYV9zZWt0b3IyW3NtYWxsLnRyYWluaW5nLmthdGVnb3JpY2tlJFNpZnJhX3Nla3RvcjE9PSI2JSJdPC0iNi05JSINCnNtYWxsLnRlc3Qua2F0ZWdvcmlja2UkU2lmcmFfc2VrdG9yMltzbWFsbC50ZXN0LmthdGVnb3JpY2tlJFNpZnJhX3Nla3RvcjE9PSIxMCUiXTwtIjEwJSINCnNtYWxsLnRlc3Qua2F0ZWdvcmlja2UkU2lmcmFfc2VrdG9yMltzbWFsbC50ZXN0LmthdGVnb3JpY2tlJFNpZnJhX3Nla3RvcjE9PSIxNCUiXTwtIjE0JSINCnNtYWxsLnRlc3Qua2F0ZWdvcmlja2UkU2lmcmFfc2VrdG9yMltzbWFsbC50ZXN0LmthdGVnb3JpY2tlJFNpZnJhX3Nla3RvcjE9PSI5JSJdPC0iNi05JSINCnNtYWxsLnRlc3Qua2F0ZWdvcmlja2UkU2lmcmFfc2VrdG9yMltzbWFsbC50ZXN0LmthdGVnb3JpY2tlJFNpZnJhX3Nla3RvcjE9PSI2JSJdPC0iNi05JSINCg0Kc21hbGwudHJhaW5pbmcua2F0ZWdvcmlja2UkU2lmcmFfc2VrdG9yMltzbWFsbC50cmFpbmluZy5rYXRlZ29yaWNrZSRTaWZyYV9zZWt0b3IxPT0iNSUiXTwtIjUlIg0Kc21hbGwudHJhaW5pbmcua2F0ZWdvcmlja2UkU2lmcmFfc2VrdG9yMltzbWFsbC50cmFpbmluZy5rYXRlZ29yaWNrZSRTaWZyYV9zZWt0b3IxPT0iNCUiXTwtIjUlIg0Kc21hbGwudHJhaW5pbmcua2F0ZWdvcmlja2UkU2lmcmFfc2VrdG9yMltzbWFsbC50cmFpbmluZy5rYXRlZ29yaWNrZSRTaWZyYV9zZWt0b3IxPT0iMyUiXTwtIjMlIg0Kc21hbGwudGVzdC5rYXRlZ29yaWNrZSRTaWZyYV9zZWt0b3IyW3NtYWxsLnRlc3Qua2F0ZWdvcmlja2UkU2lmcmFfc2VrdG9yMT09IjUlIl08LSI1JSINCnNtYWxsLnRlc3Qua2F0ZWdvcmlja2UkU2lmcmFfc2VrdG9yMltzbWFsbC50ZXN0LmthdGVnb3JpY2tlJFNpZnJhX3Nla3RvcjE9PSI0JSJdPC0iNSUiDQpzbWFsbC50ZXN0LmthdGVnb3JpY2tlJFNpZnJhX3Nla3RvcjJbc21hbGwudGVzdC5rYXRlZ29yaWNrZSRTaWZyYV9zZWt0b3IxPT0iMyUiXTwtIjMlIg0KDQpkYXRhX3NpZnJhX3Nla3Rvci5zbWFsbDwtc21hbGwudHJhaW5pbmcua2F0ZWdvcmlja2VbLGMoImRlZmF1bHQueSIsIlNpZnJhX3Nla3RvcjIiKV0NCg0KSVZfc2lmcmFfc2VrdG9yLnNtYWxsPC1jcmVhdGVfaW5mb3RhYmxlcyhkYXRhPWRhdGFfc2lmcmFfc2VrdG9yLnNtYWxsLA0KICAgICAgICAgICAgICAgICAgICAgICAgeT0iZGVmYXVsdC55IiwgDQogICAgICAgICAgICAgICAgICAgICAgICBwYXJhbGxlbD1GQUxTRSkNCg0KSVZfc2lmcmFfc2VrdG9yLnNtYWxsJFRhYmxlcw0KDQoNCmBgYA0KDQpaYWtsanVjdWplbW8gZGEsIHNla3RvciBrb2QgbWFsaWggaSBtaWtybyBwcmVkdXplY2EgbmUgaWdyYSBiYXMgYml0bnUgdWxvZ3UgYWxpIGNlbW8gdXpldGkgb3Z1IHZhcmlqYWJsdS4NCiMjIyNTaWZyYSBvcHN0aW5lOiAgDQoNCg0KYGBge3J9DQpmcmVxX3RhYmxlKHNtYWxsLnRyYWluaW5nLmthdGVnb3JpY2tlLCJTaWZyYV9vcHN0aW5lIiwiZGVmYXVsdC55IikNCmBgYA0KWmEgcG9jZXRhayBjZW1vIHNtZXN0aXRpIHN2ZSBvcHN0aW5lIGtvamUgaW1hanUgbWFuamUgb2QgMTAwIGR1em5pa2EgaSBtYW5qZSBvZCA1IGRpZm9sdGVyYSB1IGplZG51IGtsYXN1Lg0KYGBge3J9DQoNCnRlbXAudGFibGU8LWZyZXFfdGFibGUoc21hbGwudHJhaW5pbmcua2F0ZWdvcmlja2UsIlNpZnJhX29wc3RpbmUiLCJkZWZhdWx0LnkiKQ0Kb3N0YWxvLnNtYWxsLm5hbWVzPC10ZW1wLnRhYmxlW3RlbXAudGFibGUkdWt1cG5vPDEwMCwxXQ0KDQpzbWFsbC50cmFpbmluZy5rYXRlZ29yaWNrZSRTaWZyYV9vcHN0aW5lMTwtc21hbGwudHJhaW5pbmcua2F0ZWdvcmlja2UkU2lmcmFfb3BzdGluZQ0Kc21hbGwudHJhaW5pbmcua2F0ZWdvcmlja2UkU2lmcmFfb3BzdGluZTFbc21hbGwudHJhaW5pbmcua2F0ZWdvcmlja2UkU2lmcmFfb3BzdGluZSVpbiVvc3RhbG8uc21hbGwubmFtZXNdPC0ib3N0YWxvIg0Kc21hbGwudGVzdC5rYXRlZ29yaWNrZSRTaWZyYV9vcHN0aW5lMTwtc21hbGwudGVzdC5rYXRlZ29yaWNrZSRTaWZyYV9vcHN0aW5lDQpzbWFsbC50ZXN0LmthdGVnb3JpY2tlJFNpZnJhX29wc3RpbmUxW3NtYWxsLnRlc3Qua2F0ZWdvcmlja2UkU2lmcmFfb3BzdGluZSVpbiVvc3RhbG8uc21hbGwubmFtZXNdPC0ib3N0YWxvIg0KDQoNCg0Kb3N0YWxvLnNtYWxsLm5hbWVzPC10ZW1wLnRhYmxlW3RlbXAudGFibGUkYDFgPDUsMV0NCg0Kc21hbGwudHJhaW5pbmcua2F0ZWdvcmlja2UkU2lmcmFfb3BzdGluZTFbc21hbGwudHJhaW5pbmcua2F0ZWdvcmlja2UkU2lmcmFfb3BzdGluZSVpbiVvc3RhbG8uc21hbGwubmFtZXNdPC0ib3N0YWxvIg0Kc21hbGwudHJhaW5pbmcua2F0ZWdvcmlja2UkU2lmcmFfb3BzdGluZTFbc21hbGwudHJhaW5pbmcua2F0ZWdvcmlja2UkU2lmcmFfb3BzdGluZSVpbiVvc3RhbG8uc21hbGwubmFtZXNdPC0ib3N0YWxvIg0Kc21hbGwudGVzdC5rYXRlZ29yaWNrZSRTaWZyYV9vcHN0aW5lMVtzbWFsbC50ZXN0LmthdGVnb3JpY2tlJFNpZnJhX29wc3RpbmUlaW4lb3N0YWxvLnNtYWxsLm5hbWVzXTwtIm9zdGFsbyINCnNtYWxsLnRlc3Qua2F0ZWdvcmlja2UkU2lmcmFfb3BzdGluZTFbc21hbGwudGVzdC5rYXRlZ29yaWNrZSRTaWZyYV9vcHN0aW5lJWluJW9zdGFsby5zbWFsbC5uYW1lc108LSJvc3RhbG8iDQoNCg0KdGVtcC50YWJsZTwtZnJlcV90YWJsZShzbWFsbC50cmFpbmluZy5rYXRlZ29yaWNrZSwiU2lmcmFfb3BzdGluZTEiLCJkZWZhdWx0LnkiKQ0KdGVtcC50YWJsZQ0KYGBgDQpTdnN0YXZhbW8gaWggcG8gc3RvcGkgZGlmb2x0YSBkYSB2aWRpbW8gZGEgbGkgc2Ugc3RhIG1vemUgcHJvbWVuaXRpDQoNCmBgYHtyfQ0KDQpzbWFsbC50cmFpbmluZy5rYXRlZ29yaWNrZSRTaWZyYV9vcHN0aW5lMltzbWFsbC50cmFpbmluZy5rYXRlZ29yaWNrZSRTaWZyYV9vcHN0aW5lMSAlaW4lDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGMoNzAwNDEsIDcwOTU1LCA4MDQwMyldIDwtICIyJSINCnNtYWxsLnRlc3Qua2F0ZWdvcmlja2UkU2lmcmFfb3BzdGluZTJbc21hbGwudGVzdC5rYXRlZ29yaWNrZSRTaWZyYV9vcHN0aW5lMSAlaW4lDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGMoNzAwNDEsIDcwOTU1LCA4MDQwMyldIDwtICIyJSINCg0Kc21hbGwudHJhaW5pbmcua2F0ZWdvcmlja2UkU2lmcmFfb3BzdGluZTJbc21hbGwudHJhaW5pbmcua2F0ZWdvcmlja2UkU2lmcmFfb3BzdGluZTEgJWluJQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjKDcwNjUzLDcxMDk5LDcxMjQyLDc5MDY1LDgwMTI4KV0gPC0gIjMlIg0Kc21hbGwudGVzdC5rYXRlZ29yaWNrZSRTaWZyYV9vcHN0aW5lMltzbWFsbC50ZXN0LmthdGVnb3JpY2tlJFNpZnJhX29wc3RpbmUxICVpbiUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYyg3MDY1Myw3MTA5OSw3MTI0Miw3OTA2NSw4MDEyOCldIDwtICIzJSINCg0Kc21hbGwudHJhaW5pbmcua2F0ZWdvcmlja2UkU2lmcmFfb3BzdGluZTJbc21hbGwudHJhaW5pbmcua2F0ZWdvcmlja2UkU2lmcmFfb3BzdGluZTEgJWluJSBjKDcwMDMzLDcwNDgzLDcwOTA0LDcxMDQ4LDcxMjY5LDc5MDIyLDc5MDU3LDgwMTEwLDgwNDM4LDgwNDYyLCJvc3RhbG8iKV0gPC0gIjQlIg0Kc21hbGwudGVzdC5rYXRlZ29yaWNrZSRTaWZyYV9vcHN0aW5lMltzbWFsbC50ZXN0LmthdGVnb3JpY2tlJFNpZnJhX29wc3RpbmUxICVpbiUgYyg3MDAzMyw3MDQ4Myw3MDkwNCw3MTA0OCw3MTI2OSw3OTAyMiw3OTA1Nyw4MDExMCw4MDQzOCw4MDQ2Miwib3N0YWxvIildIDwtICI0JSINCg0KDQpzbWFsbC50ZXN0LmthdGVnb3JpY2tlJFNpZnJhX29wc3RpbmUyW3NtYWxsLnRlc3Qua2F0ZWdvcmlja2UkU2lmcmFfb3BzdGluZTEgJWluJQ0KYyg4OTAxMCw4MDQ2Niw4MDQyMCw4MDM1Nyw4MDMxNCw4MDE5NSw4MDE3OSw4MDE1Miw4MDA3MSw3MDY3MCw3MDQ1OSw3MDM2MCw3MDY0NSldIDwtICI1JSINCnNtYWxsLnRyYWluaW5nLmthdGVnb3JpY2tlJFNpZnJhX29wc3RpbmUyW3NtYWxsLnRyYWluaW5nLmthdGVnb3JpY2tlJFNpZnJhX29wc3RpbmUxICVpbiUNCmMoODkwMTAsODA0NjYsODA0MjAsODAzNTcsODAzMTQsODAxOTUsODAxNzksODAxNTIsODAwNzEsNzA2NzAsNzA0NTksNzAzNjAsNzA2NDUpXSA8LSAiNSUiDQoNCg0Kc21hbGwudHJhaW5pbmcua2F0ZWdvcmlja2UkU2lmcmFfb3BzdGluZTJbc21hbGwudHJhaW5pbmcua2F0ZWdvcmlja2UkU2lmcmFfb3BzdGluZTEgJWluJQ0KYyg3MDcyNiw3MDczNCw3MTEwMiw3MTIwMCw3OTAxNCw3OTA0OSw4MDA2Myw4MDQ0NildIDwtICI2JSINCnNtYWxsLnRlc3Qua2F0ZWdvcmlja2UkU2lmcmFfb3BzdGluZTJbc21hbGwudGVzdC5rYXRlZ29yaWNrZSRTaWZyYV9vcHN0aW5lMSAlaW4lDQpjKDcwNzI2LDcwNzM0LDcxMTAyLDcxMjAwLDc5MDE0LDc5MDQ5LDgwMDYzLDgwNDQ2KV0gPC0gIjYlIg0KDQoNCnNtYWxsLnRyYWluaW5nLmthdGVnb3JpY2tlJFNpZnJhX29wc3RpbmUyW3NtYWxsLnRyYWluaW5nLmthdGVnb3JpY2tlJFNpZnJhX29wc3RpbmUxICVpbiUNCmMoNzA4NzQsNzA1NjQsNzAzODYsODAzODEpXSA8LSAiNyUiDQpzbWFsbC50ZXN0LmthdGVnb3JpY2tlJFNpZnJhX29wc3RpbmUyW3NtYWxsLnRlc3Qua2F0ZWdvcmlja2UkU2lmcmFfb3BzdGluZTEgJWluJQ0KYyg3MDg3NCw3MDU2NCw3MDM4Niw4MDM4MSldIDwtICI3JSINCg0KDQpzbWFsbC50ZXN0LmthdGVnb3JpY2tlJFNpZnJhX29wc3RpbmUyW3NtYWxsLnRlc3Qua2F0ZWdvcmlja2UkU2lmcmFfb3BzdGluZTEgJWluJQ0KYyg4MDIwOSw4MDIzMyldIDwtICI4PiUiDQpzbWFsbC50cmFpbmluZy5rYXRlZ29yaWNrZSRTaWZyYV9vcHN0aW5lMltzbWFsbC50cmFpbmluZy5rYXRlZ29yaWNrZSRTaWZyYV9vcHN0aW5lMSAlaW4lDQpjKDgwMjA5LDgwMjMzKV0gPC0gIjg+JSINCg0KDQoNCmRhdGFfc2lmcmFfb3N0aW5lLnNtYWxsPC1zbWFsbC50cmFpbmluZy5rYXRlZ29yaWNrZVssYygiZGVmYXVsdC55IiwiU2lmcmFfb3BzdGluZTIiKV0NCg0KSVZfc2lmcmFfc2VrdG9yPC1jcmVhdGVfaW5mb3RhYmxlcyhkYXRhPWRhdGFfc2lmcmFfb3N0aW5lLnNtYWxsLA0KICAgICAgICAgICAgICAgICAgICAgICAgeT0iZGVmYXVsdC55IiwgDQogICAgICAgICAgICAgICAgICAgICAgICBwYXJhbGxlbD1GQUxTRSkNCklWX3NpZnJhX3Nla3RvciRUYWJsZXMNCg0KDQpgYGANCg0KcHJvYmFqbW8gZGEgcHJlZ3J1cGlzZW1vDQoNCmBgYHtyfQ0KDQpzbWFsbC50cmFpbmluZy5rYXRlZ29yaWNrZSRTaWZyYV9vcHN0aW5lMzwtc21hbGwudHJhaW5pbmcua2F0ZWdvcmlja2UkU2lmcmFfb3BzdGluZTIgDQpzbWFsbC50cmFpbmluZy5rYXRlZ29yaWNrZSRTaWZyYV9vcHN0aW5lM1tzbWFsbC50cmFpbmluZy5rYXRlZ29yaWNrZSRTaWZyYV9vcHN0aW5lMiAlaW4lDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGMoIjQlIiwiNSUiKV0gPC0gIjQtNSUiDQpzbWFsbC50ZXN0LmthdGVnb3JpY2tlJFNpZnJhX29wc3RpbmUzPC1zbWFsbC50ZXN0LmthdGVnb3JpY2tlJFNpZnJhX29wc3RpbmUyIA0Kc21hbGwudGVzdC5rYXRlZ29yaWNrZSRTaWZyYV9vcHN0aW5lM1tzbWFsbC50ZXN0LmthdGVnb3JpY2tlJFNpZnJhX29wc3RpbmUyICVpbiUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYygiNCUiLCI1JSIpXSA8LSAiNC01JSINCiNzbWFsbC50cmFpbmluZy5rYXRlZ29yaWNrZSRTaWZyYV9vcHN0aW5lM1soc21hbGwudHJhaW5pbmcua2F0ZWdvcmlja2UkU2lmcmFfb3BzdGluZTIgJWluJQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjYygiNSUiLCI2JSIsIjclIiwiOD4lIikpXSA8LSAiaGlnaCUiDQoNCmRhdGFfc2lmcmFfb3N0aW5lLnNtYWxsMjwtc21hbGwudHJhaW5pbmcua2F0ZWdvcmlja2VbLGMoImRlZmF1bHQueSIsIlNpZnJhX29wc3RpbmUzIildDQoNCklWX3NpZnJhX3Nla3RvcjI8LWNyZWF0ZV9pbmZvdGFibGVzKGRhdGE9ZGF0YV9zaWZyYV9vc3RpbmUuc21hbGwyLA0KICAgICAgICAgICAgICAgICAgICAgICAgeT0iZGVmYXVsdC55IiwgDQogICAgICAgICAgICAgICAgICAgICAgICBwYXJhbGxlbD1GQUxTRSkNCklWX3NpZnJhX3Nla3RvcjIkVGFibGVzICAgICAgICANCmZyZXFfdGFibGUoc21hbGwudHJhaW5pbmcua2F0ZWdvcmlja2UsIlNpZnJhX29wc3RpbmUzIiwiZGVmYXVsdC55IikgICAgICAgIA0KDQpgYGANCmNhayBpIG92YWtvIHJhc3BvcmVkamVuZSBpbWFqdSBzbGFidSBwcmVkaWt0aXZudSBtb2MuIHBva3VzYXZhbW8gc2FkYSBwbyByYXp2aWplbm9zdGkgb3BzdGluYSwgb3ZvIG5lY2VtbyB1emltYXRpIGplciBuZW1hIG5la29nIGxvZ2ljbm9nIG9iamFzbmplbmphIGEgZGlza3JpbWluYXRpdm5vc3QgaSBuaWplIHZlbGlrYQ0KDQoNCmBgYHtyfQ0KI3VjaXRhdmFtIHByaXByZW1samVudSB0YWJlbHUgc2Ega2F0ZWdvcmlqYW1hIHJhenZpamVub3N0aQ0Kb3BzdGluZV9yYXp2aWplbm9zdCA8LSByZWFkX2RlbGltKCJDOi9Vc2Vycy9taWxvcy5jaXBvdmljL0Rlc2t0b3AvUHJvamVrdGkvRWFybHkgd2FybmluZy9SYXp2b2puaSBmb2xkZXIvQm90dG9tIFVwL0tvcmFrIDUvb3BzdGluZV9yYXp2aWplbm9zdC5jc3YiLCANCiI7IiwgZXNjYXBlX2RvdWJsZSA9IEZBTFNFLCB0cmltX3dzID0gVFJVRSkNCg0KI2piZyBtb3JhbW8gdm9kaXRpIHJhY3VuYSBvIHJlZG9zbGVkdSBvdmRlISEhISEhDQpzbWFsbC50cmFpbmluZy5rYXRlZ29yaWNrZSRpZCAgPC0gMTpucm93KHNtYWxsLnRyYWluaW5nLmthdGVnb3JpY2tlKQ0Kc21hbGwudGVzdC5rYXRlZ29yaWNrZSRpZCAgPC0gMTpucm93KHNtYWxsLnRlc3Qua2F0ZWdvcmlja2UpDQoNCnNtYWxsLnRyYWluaW5nLmthdGVnb3JpY2tlPC1tZXJnZShzbWFsbC50cmFpbmluZy5rYXRlZ29yaWNrZSxvcHN0aW5lX3JhenZpamVub3N0LGFsbC54ID0gVCkNCnNtYWxsLnRlc3Qua2F0ZWdvcmlja2U8LW1lcmdlKHNtYWxsLnRlc3Qua2F0ZWdvcmlja2Usb3BzdGluZV9yYXp2aWplbm9zdCxhbGwueCA9IFQpDQoNCnNtYWxsLnRyYWluaW5nLmthdGVnb3JpY2tlPC1zbWFsbC50cmFpbmluZy5rYXRlZ29yaWNrZVtvcmRlcihzbWFsbC50cmFpbmluZy5rYXRlZ29yaWNrZSRpZCksIF1bLGlkOj1OVUxMXQ0Kc21hbGwudGVzdC5rYXRlZ29yaWNrZTwtc21hbGwudGVzdC5rYXRlZ29yaWNrZVtvcmRlcihzbWFsbC50ZXN0LmthdGVnb3JpY2tlJGlkKSwgXVssaWQ6PU5VTExdDQoNCg0KDQpkYXRhX3JhenZpamVub3N0X29zdGluZS5zbWFsbDI8LXNtYWxsLnRyYWluaW5nLmthdGVnb3JpY2tlWyxjKCJkZWZhdWx0LnkiLCJSYXp2aWplbm9zdCIpXQ0KZGF0YV9yYXp2aWplbm9zdF9vc3RpbmUuc21hbGwyJFJhenZpamVub3N0PC1hcy5jaGFyYWN0ZXIoZGF0YV9yYXp2aWplbm9zdF9vc3RpbmUuc21hbGwyJFJhenZpamVub3N0KQ0KDQpJVl9yYXp2aWplbm9zdDI8LWNyZWF0ZV9pbmZvdGFibGVzKGRhdGE9ZGF0YV9yYXp2aWplbm9zdF9vc3RpbmUuc21hbGwyLA0KICAgICAgICAgICAgICAgICAgICAgICAgeT0iZGVmYXVsdC55IiwgDQogICAgICAgICAgICAgICAgICAgICAgICBwYXJhbGxlbD1GQUxTRSkNCg0KSVZfcmF6dmlqZW5vc3QyJFRhYmxlcyAgIA0KZnJlcV90YWJsZShzbWFsbC50cmFpbmluZy5rYXRlZ29yaWNrZSwiUmF6dmlqZW5vc3QiLCJkZWZhdWx0LnkiKQ0KYGBgDQpiZXpuYWNham5vLCBrb25hY2FuIHpha2xqdWNhayBqZSBkYSBpZGVtbyBzYSB2YXJpamFibG9tIFNpZnJhX29wc3RpbmUzDQojIyMjU3RyYW5pIGludmVzdGl0b3IgIA0KDQpQb2dsZWRham1vIHBydm8gZnJla3ZlbmNpb251IHRhYmVsdQ0KDQpgYGB7cn0NCmZyZXFfdGFibGUoc21hbGwudHJhaW5pbmcua2F0ZWdvcmlja2UsIlN0cmFuaV9pbnZlc3RpdG9yIiwiZGVmYXVsdC55IikNCmBgYA0KUG9zdG9qaSAgcmF6bGlrYSwgaW1hanVjaSB1IHZpZHUgZGEgb3ZkZSBpbWFtbyBzYW1vIGR2ZSB2YXJpamFibGUsIHRvIGplIGkgb2Nla2l2YW5vLCBoYWpkZSBkYSB2aWRpbW8gSVY6DQpgYGB7cn0NCldPRVRhYmxlKFg9YXMuZmFjdG9yKHNtYWxsLnRyYWluaW5nLmthdGVnb3JpY2tlJFN0cmFuaV9pbnZlc3RpdG9yKSxZPShzbWFsbC50cmFpbmluZy5rYXRlZ29yaWNrZSRkZWZhdWx0LnktMSkqKC0xKSkNCmBgYA0KbmVtYSB1dGljYWphDQoNCiMjIyNWZWxpY2luYQ0KDQoNCmBgYHtyfQ0KV09FVGFibGUoWD1hcy5mYWN0b3Ioc21hbGwudHJhaW5pbmcua2F0ZWdvcmlja2UkVmVsaWNpbmEpLFk9KHNtYWxsLnRyYWluaW5nLmthdGVnb3JpY2tlJGRlZmF1bHQueS0xKSooLTEpKQ0KYGBgDQptYXJnaW5hbG5vDQoNCg0KDQoNCiMjI0V2YWx1YWNpamEgcmVncmVzaWplDQoNCkRvc2FkYXNuamkgcmV6dWx0YXRpOg0KDQpPdHBhZGFuamUgdXNsZWQgYE5BYCB2cmVkbm9zdGksIHByZXppdmVsZSBzdSBzbGVkZWNlIHZhcmlqYWJsZToNCmBgYHtyfQ0Kc3VtbWFyeV90YWJsZS5zbWFsbDwtYXMuZGF0YS5mcmFtZShzdW1tYXJ5X3RhYmxlLnNtYWxsKQ0KcHJleml2ZWxpLk5BLnNtYWxsPC1yb3duYW1lcyhzdW1tYXJ5X3RhYmxlLnNtYWxsW3N1bW1hcnlfdGFibGUuc21hbGwkTkFzcGVyY2VudDwxMCxdKQ0KYGBgDQoNCkNpc2NlbmplIHVzbGVkIGtvcmVsYWNpamEgaSBBVVJPQy1hIG1hbmplZyBvZCAwLjU1DQpgYGB7cn0NCg0KcHJleml2ZWxpLmNvcnIuQVVDLnNtYWxsPC1yb3cubmFtZXMoY2xlYW5fY29yLnNtYWxsKQ0KDQpgYGANCg0KUHJlc2VrIG92YSBkdmEgbmFzdGF2bGphIHUgbXVsdGl2YXJpYXRlLg0KDQpgYGB7cn0NCm9kYWJyYW5pLnNtYWxsPC11bmlxdWUoYygiUmFjaW9fbm92Y2FuZV9saWt2aWRub3N0aV8oQ2FzaF9yYXRpbykiLCBjKGludGVyc2VjdChwcmV6aXZlbGkuTkEuc21hbGwscHJleml2ZWxpLmNvcnIuQVVDLnNtYWxsKSkpKQ0KYGBgDQoNCg0KDQojIyNLcmVpcmFtbyB6YXZyc25pIHV6b3JhazogIA0KX19fX19fX19fX19fX19fX19fX19fXyAgDQoNClRyZXRtYW4gbmVkb3N0YWp1Y2loIGkgdHJldG1hbiBhdXRsYWplcmEsIHBvdG9tIGRvZGFqZW1vIGthdGVnb3JpY2tlDQoNCmBgYHtyfQ0KZmluYWxuaV9zbWFsbDwtc21hbGwudHJhaW5pbmdbLGMob2RhYnJhbmkuc21hbGwpLHdpdGg9Rl0NCmZpbmFsbmlfc21hbGwudGVzdDwtc21hbGwudGVzdFssYyhvZGFicmFuaS5zbWFsbCksd2l0aD1GXQ0KI2ZpbmFsbmlfbHJnZTwtY2JpbmQuZGF0YS5mcmFtZShmaW5hbG5pX2xyZ2UsQXNzZXRfdHVybm92ZXIkQXNzZXRfdHVybm92ZXIudHIsUG9rcmljZV9uZXRvX2thbWF0YSRQb2tyaWNlX25ldG9fa2FtYXRhLnRyKQ0KDQpmaW5hbG5pX3NtYWxsPC1hcy5kYXRhLnRhYmxlKHNhcHBseShmaW5hbG5pX3NtYWxsLHJlcGxhY2Vfb3V0bGllcl93aXRoX3F1YW50aWxlKSkNCmZpbmFsbmlfc21hbGwudGVzdDwtYXMuZGF0YS50YWJsZShzYXBwbHkoZmluYWxuaV9zbWFsbC50ZXN0LHJlcGxhY2Vfb3V0bGllcl93aXRoX3F1YW50aWxlKSkNCg0KZmluYWxuaV9zbWFsbCRkZWZhdWx0Lnk8LXNtYWxsLnRyYWluaW5nJGRlZmF1bHQueQ0KZmluYWxuaV9zbWFsbDwtcmVwbGFjZV9taXNzaW5nX3dpdGhfa25uKGZpbmFsbmlfc21hbGwpDQpmaW5hbG5pX3NtYWxsJGRlZmF1bHQueTwtTlVMTA0KDQpmaW5hbG5pX3NtYWxsLnRlc3QkZGVmYXVsdC55PC1zbWFsbC50ZXN0JGRlZmF1bHQueQ0KZmluYWxuaV9zbWFsbC50ZXN0PC1yZXBsYWNlX21pc3Npbmdfd2l0aF9rbm4oZmluYWxuaV9zbWFsbC50ZXN0LHRyYWluaW5nID0gRikNCmZpbmFsbmlfc21hbGwudGVzdCRkZWZhdWx0Lnk8LU5VTEwNCmBgYA0KDQoNCm9wY2lvbm8sIHRyYW5zZm9ybWFjaWphDQpgYGB7cn0NCkFBPC1kYXRhLmZyYW1lKDE6bnJvdyhmaW5hbG5pX3NtYWxsKSk7bj0xDQoNCmZvcihpIGluIG5hbWVzKGZpbmFsbmlfc21hbGwpWyJkZWZhdWx0LnkiICE9IG5hbWVzKGZpbmFsbmlfc21hbGwpXSkgew0KDQogIG4gPSBuICsgMQ0KICB0bXAgPC0gY2FsaWJyYXRlX3BhcmFtZXRlcnMoZmluYWxuaV9zbWFsbCwgaSwgImRlZmF1bHQueSIpDQogIEFBIDwtIGNiaW5kLmRhdGEuZnJhbWUoQUEsIHRtcFtbN11dKQ0KICBuYW1lcyhBQSlbbl0gPC0gbmFtZXMoZmluYWxuaV9zbWFsbClbbl0NCn0NCg0KDQpmaW5hbG5pX3NtYWxsIDwtIEFBDQpyZW1vdmUoQUEpDQpmaW5hbG5pX3NtYWxsWywgMV0gPC0gTlVMTA0KZmluYWxuaV9zbWFsbCRkZWZhdWx0LnkgPC0gZGVmYXVsdC55DQpmaW5hbG5pX3NtYWxsIDwtIGFzLmRhdGEudGFibGUoZmluYWxuaV9zbWFsbCkNCmBgYA0KDQoNCkRvZGFqZW1vIGR2ZSBrYXRlZ29yaWNrZToNCmBgYHtyfQ0KI3NwYWphbW8gc2Ega2F0ZWdvcmlja2ltIGkgc2tpZGFtbyBwYXIgdmlza292YSBrYXRlZ29yaWNraWgsIHZlbGljaW5hLCB0b3RhbA0KDQpmaW5hbG5pX3NtYWxsIDwtDQogIGNiaW5kLmRhdGEuZnJhbWUoZmluYWxuaV9zbWFsbCwgc21hbGwudHJhaW5pbmcua2F0ZWdvcmlja2VbLCBjKCJWZWxpY2luYSIsIlNpZnJhX3Nla3RvcjIiLCJTaWZyYV9vcHN0aW5lMyIpXSkNCmZpbmFsbmlfc21hbGwudGVzdCA8LQ0KICBjYmluZC5kYXRhLmZyYW1lKGZpbmFsbmlfc21hbGwudGVzdCwgc21hbGwudGVzdC5rYXRlZ29yaWNrZVssIGMoIlZlbGljaW5hIiwiU2lmcmFfc2VrdG9yMiIsIlNpZnJhX29wc3RpbmUzIildKQ0KDQoNCiNwcmV0dmFyYW0ga2F0ZWdvcmlja2UgdSBmYWt0b3IgZGEgYmkgaWggZ2xtIHBvc21hdHJhbyBrYW8ga2F0ZWdvcmlja2UNCmZpbmFsbmlfc21hbGwkU2lmcmFfc2VrdG9yMiA8LSBhcy5mYWN0b3IoZmluYWxuaV9zbWFsbCRTaWZyYV9zZWt0b3IyKQ0KZmluYWxuaV9zbWFsbCRWZWxpY2luYSA8LWFzLmZhY3RvcihmaW5hbG5pX3NtYWxsJFZlbGljaW5hKQ0KZmluYWxuaV9zbWFsbCRTaWZyYV9vcHN0aW5lMyA8LWFzLmZhY3RvcihmaW5hbG5pX3NtYWxsJFNpZnJhX29wc3RpbmUzKQ0KDQpmaW5hbG5pX3NtYWxsLnRlc3QkU2lmcmFfc2VrdG9yMiA8LSBhcy5mYWN0b3IoZmluYWxuaV9zbWFsbC50ZXN0JFNpZnJhX3Nla3RvcjIpDQpmaW5hbG5pX3NtYWxsLnRlc3QkVmVsaWNpbmEgPC1hcy5mYWN0b3IoZmluYWxuaV9zbWFsbC50ZXN0JFZlbGljaW5hKQ0KZmluYWxuaV9zbWFsbC50ZXN0JFNpZnJhX29wc3RpbmUzIDwtYXMuZmFjdG9yKGZpbmFsbmlfc21hbGwudGVzdCRTaWZyYV9vcHN0aW5lMykNCg0KDQpgYGANCg0KDQoNCg0KDQpEdWdvIG9jZWtpdmFuaSB0cmVudXRhazoNCg0KYGBge3J9DQoNCm1vZGVsLm51bGwuc21hbGwgPSBnbG0oZGVmYXVsdC55IH4gMSwNCiAgICAgICAgICAgICAgICAgZGF0YT1maW5hbG5pX3NtYWxsLA0KICAgICAgICAgICAgICAgICBmYW1pbHkgPSBiaW5vbWlhbChsaW5rPSJsb2dpdCIpDQogICAgICAgICAgICAgICAgICkNCg0KbW9kZWwuZnVsbC5zbWFsbCA9IGdsbShkZWZhdWx0LnkgfiAuLA0KICAgICAgICAgICAgICAgICBkYXRhPWZpbmFsbmlfc21hbGwsDQogICAgICAgICAgICAgICAgIGZhbWlseSA9IGJpbm9taWFsKGxpbms9ImxvZ2l0IikNCiAgICAgICAgICAgICAgICAgKQ0KICAgIA0Kc3RlcChtb2RlbC5udWxsLnNtYWxsLA0KICAgICBzY29wZSA9IGxpc3QodXBwZXI9bW9kZWwuZnVsbC5zbWFsbCxsb3dlcj1tb2RlbC5udWxsLnNtYWxsKSwNCiAgICAgICAgICAgICBkaXJlY3Rpb249ImZvcndhcmQiLA0KICAgICAgICAgICAgIA0KICAgICAgICAgICAgIGRhdGE9ZmluYWxuaV9zbWFsbCx0cmFjZT0wKQ0KYGBgDQoNCmBgYHtyfQ0KbW9kZWwxLnNtYWxsIDwtZ2xtKGZvcm11bGEgPSBkZWZhdWx0LnkgfiBUMTIgKyBTdG9wYV9wcmlub3NhX25hX3VrdXBuYV9zcmVkc3R2YV9wcmVfb3BvcmV6aXZhbmphICsgDQogICAgQXNzZXRfdHVybm92ZXIgKyBgUmFjaW9fbm92Y2FuZV9saWt2aWRub3N0aV8oQ2FzaF9yYXRpbylgICsgDQogICAgU2lmcmFfb3BzdGluZTMgKyB1ZGVvX3Vfa2FwaXRhbHUgKyBTdGVwZW5femFkdXplbm9zdGkgKyBWcmVtZV9rcmVkaXRpcmFuamFfa3VwYWNhICsgDQogICAgU2lmcmFfc2VrdG9yMiArIGBSYWNpb19wb2tyaWNhX2thbWF0YV96YXJhZG9tX3ByZV9rYW1hdGFfaV9wb3JlemFfKEludGVyZXN0X0NvdmVyYWdlX1JhdGlvKWAgKyANCiAgICBCcm9qX3phcG9zbGVuaWggKyBSYWNpb19wb2tyaWNhX29icnRuZV9pbW92aW5lICsgVmVsaWNpbmEgKyANCiAgICBUMTQgKyBTdG9wYV9wcmlub3NhX25hX3NvcHN0dmVuaV9rYXBpdGFsX3ByZV9vcG9yZXppdmFuamEsIA0KICAgIGZhbWlseSA9IGJpbm9taWFsKGxpbmsgPSAibG9naXQiKSwgZGF0YSA9IGZpbmFsbmlfc21hbGwpDQogIA0KbW9kZWwxLnNtYWxsLmRhdGEuZnJhbWU8LWRhdGEuZnJhbWUoZml0MT1tb2RlbDEuc21hbGwkZml0dGVkLnZhbHVlcywgZGlmMT1tb2RlbDEuc21hbGwkbW9kZWwkZGVmYXVsdC55KQ0KDQpgYGANCg0KDQoNCg0KYGBge3J9DQpzdGVwKG1vZGVsLmZ1bGwuc21hbGwsDQogICAgIHNjb3BlID0gbGlzdChsb3dlcj1tb2RlbC5mdWxsLnNtYWxsLHVwcGVyPW1vZGVsLm51bGwuc21hbGwpLA0KICAgICAgICAgICAgIGRpcmVjdGlvbj0iYmFja3dhcmQiLA0KICAgICAgICAgICAgIGRhdGE9ZmluYWxuaV9zbWFsbCwgdHJhY2U9MCkNCmBgYA0KYGBge3J9DQogbW9kZWwyLnNtYWxsPSAgZ2xtKGZvcm11bGEgPSBkZWZhdWx0LnkgfiBgUmFjaW9fbm92Y2FuZV9saWt2aWRub3N0aV8oQ2FzaF9yYXRpbylgICsgDQogICAgQnJval96YXBvc2xlbmloICsgU3RlcGVuX3phZHV6ZW5vc3RpICsgYFJhY2lvX3Bva3JpY2Ffa2FtYXRhX3phcmFkb21fcHJlX2thbWF0YV9pX3BvcmV6YV8oSW50ZXJlc3RfQ292ZXJhZ2VfUmF0aW8pYCArIA0KICAgIFJhY2lvX3Bva3JpY2Ffb2JydG5lX2ltb3ZpbmUgKyBHb3Rvdmluc2tpX2Npa2x1c18xICsgVnJlbWVfa3JlZGl0aXJhbmphX2t1cGFjYSArIA0KICAgIFZyZW1lX25hcGxhdGVfcG90cmF6aXZhbmphICsgVnJlbWVfcGxhY2FuamFfZG9iYXZsamFjaW1hICsgDQogICAgQXNzZXRfdHVybm92ZXIgKyBTdG9wYV9wcmlub3NhX25hX3NvcHN0dmVuaV9rYXBpdGFsX3ByZV9vcG9yZXppdmFuamEgKyANCiAgICBTdG9wYV9wcmlub3NhX25hX3VrdXBuYV9zcmVkc3R2YV9wcmVfb3BvcmV6aXZhbmphICsgVDEyICsgDQogICAgVDE0ICsgdWRlb191X2thcGl0YWx1ICsgVmVsaWNpbmEgKyBTaWZyYV9zZWt0b3IyICsgU2lmcmFfb3BzdGluZTMsIA0KICAgIGZhbWlseSA9IGJpbm9taWFsKGxpbmsgPSAibG9naXQiKSwgZGF0YSA9IGZpbmFsbmlfc21hbGwpDQoNCm1vZGVsMi5zbWFsbC5kYXRhLmZyYW1lPWRhdGEuZnJhbWUoZml0Mj1tb2RlbDIuc21hbGwkZml0dGVkLnZhbHVlcywgZGlmMj1tb2RlbDIuc21hbGwkbW9kZWwkZGVmYXVsdC55KQ0KDQpgYGANCg0KV2FsZCBzdGF0aXN0aWs6DQoNCmBgYHtyfQ0KbGlicmFyeShjYXIpDQoNCkFub3ZhKG1vZGVsMS5zbWFsbCwgdHlwZT0iSUkiLCB0ZXN0PSJXYWxkIikNCmBgYA0KTGFuZ3JhbmdlIG11bHRpcGxpZXIgdGVzdDoNCg0KYGBge3J9DQphbm92YShtb2RlbDEuc21hbGwsDQogICAgICBtb2RlbC5udWxsLnNtYWxsLA0KICAgICAgdGVzdD0iQ2hpc3EiKQ0KYGBgDQoNCg0KDQpEcnVnaSBuYWNpbg0KDQpgYGB7cn0NCiBhdXJvYy4xPC1hdWMoDQogICAgICBhcy5udW1lcmljKG1vZGVsMS5zbWFsbC5kYXRhLmZyYW1lJGRpZjEpLA0KICAgICAgYXMubnVtZXJpYyhtb2RlbDEuc21hbGwuZGF0YS5mcmFtZSRmaXQxKSkNCg0KIGF1cm9jLjI8LWF1YygNCiAgICAgIGFzLm51bWVyaWMobW9kZWwyLnNtYWxsLmRhdGEuZnJhbWUkZGlmMiksDQogICAgICBhcy5udW1lcmljKG1vZGVsMi5zbWFsbC5kYXRhLmZyYW1lJGZpdDIpKQ0KIA0KIGMoYXVyb2MuMSxhdXJvYy4yKQ0KDQpgYGANCg0KIyMjdmFsaWRhY2lvbmkgdXpvcmFrICANCg0KYGBge3J9DQoNCm1vZGVsMS5zbWFsbC5wcmVkPC1hcy5udW1lcmljKHByZWRpY3QobW9kZWwxLnNtYWxsLCBuZXdkYXRhID0gZmluYWxuaV9zbWFsbC50ZXN0LCB0eXBlID0gInJlc3BvbnNlIikpDQpkaWYuc21hbGwudmFsaWQ8LXNtYWxsLnRlc3QkZGVmYXVsdC55DQoNCm1vZGVsMi5zbWFsbC5wcmVkPC1hcy5udW1lcmljKHByZWRpY3QobW9kZWwyLnNtYWxsLCBuZXdkYXRhID0gZmluYWxuaV9zbWFsbC50ZXN0LCB0eXBlID0gInJlc3BvbnNlIikpDQoNCg0KDQphdXJvYy4xLnByZWQ8LWF1YyhkaWYuc21hbGwudmFsaWQsIG1vZGVsMS5zbWFsbC5wcmVkKQ0KYXVyb2MuMi5wcmVkPC1hdWMoZGlmLnNtYWxsLnZhbGlkLCBtb2RlbDIuc21hbGwucHJlZCkNCmMoYXVyb2MuMS5wcmVkLGF1cm9jLjIucHJlZCkNCmBgYA0KDQoNCg0KDQoNCg0KW14zXTogVmlkaSBSYXRpbmcgTW9kZWxzIGFuZCBWYWxpZGF0aW9uIC0gIE9lc3RlcnJlaWNoaXNjaGUgTmF0aW9uYWxiYW5rIChPZU5CKS4gIA0KW140XTogSGF5ZGVuLCBFLiwgJiBQb3JhdGgsIEQuICgyMDExKS4gU3RhdGlzdGljYWwgTWV0aG9kcyB0byBEZXZlbG9wIFJhdGluZyBNb2RlbHMuIEluIEIuIEVuZ2VsbWFubiwgYW5kIFIuIFJhdWhtZWllciAoRWRzLiksIFRoZSBCYXNlbCBJSSBSaXNrIFBhcmFtZXRlcnM6IEVzdGltYXRpb24sIFZhbGlkYXRpb24sIFN0cmVzcyBUZXN0aW5nIOKAkyB3aXRoIEFwcGxpY2F0aW9ucyB0byBMb2FuIFJpc2sgTWFuYWdlbWVudCAocHAuIDHigJMxMikuIE5ldyBZb3JrOiBTcHJpbmdlci4gIA0KW141XTogRGV2ZWxvcGluZywgVmFsaWRhdGluZyBhbmQgVXNpbmcgSW50ZXJuYWwgUmF0aW5ncyAtIERlIExhdXJlbnRpcw0KW142XTogQ3JlZGl0IFJpc2sgTW9kZWxpbmcgdXNpbmcgRXhjZWwgYW5kIFZCQSwgMm5kIEVkaXRpb24gLSBHdW50ZXIgTMO2ZWZmbGVyLCBQZXRlciBOLiBQb3NjaC4NClteN106IFRoZSBCYXNlbCBJSSBSaXNrIFBhcmFtZXRlcnM6IEVzdGltYXRpb24sIFZhbGlkYXRpb24sIFN0cmVzcyBUZXN0aW5nIOKAkyB3aXRoIEFwcGxpY2F0aW9ucyB0byBMb2FuIFJpc2sgTWFuYWdlbWVudCwgQ2hhcHRlciAzLiBOZXcgWW9yazogU3ByaW5nZXIuDQpbXjhdOiBDcmVkaXQgUmlzayBTY29yZWNhcmRzOiBEZXZlbG9waW5nIGFuZCBJbXBsZW1lbnRpbmcgSW50ZWxsaWdlbnQgQ3JlZGl0IFNjb3JpbmcsIGJ5IE5hZWVtIFNpZGRpcWkgDQoNCg0KYGBge3J9DQpteS52YXJzLnNtYWxsIDwtZmluYWxuaV9zbWFsbCMgYSBtYXRyaXggd2l0aCB5b3VyIDE0IGRpZmZlcmVudCBlbnZpcm9ubWVudGFsIHZhcmlhYmxlcw0KbmFtZXMobXkudmFycy5zbWFsbClbYygxLCA0KV0gPC0NCiAgYygiUmFjaW9fbm92Y2FuZV9saWt2aWRub3N0aSIsDQogICJSYWNpb19wb2tyaWNhX2thbWF0YV96YXJhZG9tX3ByZV9rYW1hdGFfaV9wb3JlemEiKQ0KDQpteS52YXJzLnNtYWxsLnZhbGlkIDwtIGZpbmFsbmlfc21hbGwudGVzdCMNCm5hbWVzKG15LnZhcnMuc21hbGwudmFsaWQpW2MoMSwgNCldIDwtDQogIGMoIlJhY2lvX25vdmNhbmVfbGlrdmlkbm9zdGkiLA0KICAiUmFjaW9fcG9rcmljYV9rYW1hdGFfemFyYWRvbV9wcmVfa2FtYXRhX2lfcG9yZXphIikNCg0KbXkudmFycy5zbWFsbCRkZWZhdWx0Lnk9TlVMTA0KDQpsaWJyYXJ5KHNwZWVkZ2xtKQ0KbnZhci5zbWFsbDwtbmNvbChteS52YXJzLnNtYWxsKQ0KDQojY29sbmFtZXMobXkudmFycykgPC0gcGFzdGUoInZhciIsIDE6bnZhciwgc2VwPSIiKSAjIGFkZCByb3cgbmFtZXMgInZhcjEiIC0gInZhcjE0Ig0KbXkuZ3JhZC5kYXRhLnNtYWxsIDwtIDE6bnZhci5zbWFsbA0Kc3VtLnZhcnMuc21hbGwgPC0gdmVjdG9yKCkNCmF1Yy5wLnNtYWxsIDwtIHZlY3RvcigpDQphdWMucHJlZC5zbWFsPC12ZWN0b3IoKQ0KY29tYi5tYXQuc21hbGwgPC0gbWF0cml4KG51bWVyaWMoMCksIG5yb3c9bnZhci5zbWFsbCwgbmNvbD0wKSAjIGluaXRpYWxpc2UgdGhlIG1hdHJpeCBjb250YWluaW5nIGFsbCBjb21iaW5hdGlvbnMNCmRpZi5zbWFsbC52YWxpZDwtc21hbGwudGVzdCRkZWZhdWx0LnkNCg0KDQpmb3IgKCBpIGluIDE6bnZhci5zbWFsbCApIHsgIyBnZW5lcmF0ZSBhbmQgc3RvcmUgYWxsIHBvc3NpYmxlIGNvbWJpbmF0aW9uIG9mIHN1bXMgb2YgdGhlIDE0IHZhcmlhYmxlcw0KICANCiAgdC5tYXQuc21hbGwgPC0gY29tYm4obXkuZ3JhZC5kYXRhLnNtYWxsLCBtPWkpDQogIA0KICBjb21iLm1hdC5zbWFsbCA8LSBjYmluZChjb21iLm1hdC5zbWFsbCwgcmJpbmQodC5tYXQuc21hbGwsIG1hdHJpeChOQSwgbmNvbD1kaW0odC5tYXQuc21hbGwpWzJdICwgbnJvdz1udmFyLnNtYWxsLWkpKSkNCn0NCg0KY29sbm1zLnNtYWxsPC1jb2xuYW1lcyhteS52YXJzLnNtYWxsKQ0KbXkudmFycy5zbWFsbCRkZWZhdWx0Lnk9c21hbGwudHJhaW5pbmckZGVmYXVsdC55DQoNCm51bS5vZi52YXJzLnNtYWxsIDwtIGFwcGx5KGFzLmRhdGEuZnJhbWUoY29tYi5tYXQuc21hbGwpLGMoMikNCiAgICAgICAgICAgICAgICAgICAgICAsIGZ1bmN0aW9uKHgpIHsNCiAgICAgICAgICAgICAgICAgICAgICBzdW0oYXMubnVtZXJpYyghaXMubmEoeCkpKQ0KICAgICAgICAgICAgICAgICAgICAgIH0pDQoNCmZvciAoIGogaW4gMTpkaW0oY29tYi5tYXQuc21hbGwpWzJdICkgeyAjIGNhbGN1bGF0ZSBhbmQgc3RvcmUgdGhlIFIyIGZvciBhbGwgY29tYmluYXRpb25zDQogIA0KICAjc3VtLnZlYyA8LSByb3dTdW1zKG15LnZhcnNbLCBjb21iLm1hdFssIGpdXSwgbmEucm09VFJVRSkNCg0KICBzdW0udmFycy5zbWFsbFtqXSA8LSBwYXN0ZSggY29sbm1zLnNtYWxsW2MobmEub21pdChjb21iLm1hdC5zbWFsbFssIGpdKSldLCANCiAgICBjb2xsYXBzZT0iKyIpDQogIHJlbGFjaWphLnNtYWxsPWFzLmZvcm11bGEocGFzdGUoImRlZmF1bHQueSB+ICIsc3VtLnZhcnMuc21hbGxbal0sc2VwID0gIiIpKQ0KICBtb2RlbC5zbWFsbCA9IHNwZWVkZ2xtKHJlbGFjaWphLnNtYWxsLA0KICAgICAgICAgICAgICAgICAgIGRhdGEgPSBteS52YXJzLnNtYWxsLA0KICAgICAgICAgICAgICAgICAgIHk9VFJVRSwNCiAgICAgICAgICAgICAgICAgICBmaXR0ZWQgPSBUUlVFLA0KICAgICAgICAgICAgICAgICAgIGZhbWlseSA9IGJpbm9taWFsKGxpbmsgPSAibG9naXQiKSkNCg0KICBtb2RlbC5zbWFsbC5kYXRhLmZyYW1lPWRhdGEuZnJhbWUoZml0PWZpdHRlZC52YWx1ZXMobW9kZWwuc21hbGwpLCBkaWY9bW9kZWwuc21hbGwkeSkNCiAgI2Jyb3dzZXIoKQ0KICBhdWMucC5zbWFsbFtqXSA8LSBhdWNfcm9jKGFzLm51bWVyaWMobW9kZWwuc21hbGwuZGF0YS5mcmFtZSRmaXQpLGFzLm51bWVyaWMobW9kZWwuc21hbGwuZGF0YS5mcmFtZSRkaWYpKQ0KICAjYXVjLnAuc21hbGxbal0gPC1mYXN0QVVDKGFzLm51bWVyaWMobW9kZWwuc21hbGwuZGF0YS5mcmFtZSRmaXQpLGFzLm51bWVyaWMobW9kZWwuc21hbGwuZGF0YS5mcmFtZSRkaWYpKQ0KICANCiAgDQogIG1vZGVsLnNtYWxsLnByZWQ8LWFzLm51bWVyaWMocHJlZGljdChtb2RlbC5zbWFsbCwgbmV3ZGF0YSA9IG15LnZhcnMuc21hbGwudmFsaWQsIHR5cGUgPSAicmVzcG9uc2UiKSkNCiAgDQogIGF1Yy5wcmVkLnNtYWxbal08LWF1Y19yb2MoIG1vZGVsLnNtYWxsLnByZWQsZGlmLnNtYWxsLnZhbGlkKQ0KICAjYXVjLnByZWQuc21hbFtqXTwtZmFzdEFVQyggbW9kZWwuc21hbGwucHJlZCxkaWYuc21hbGwudmFsaWQpDQogIA0KICBpZihqICVpbiUgcm91bmQoc2VxKGZyb209MSwgdG89ZGltKGNvbWIubWF0LnNtYWxsKVsyXSxsZW5ndGgub3V0ID0gMTAwKSkpIHByaW50KGovZGltKGNvbWIubWF0LnNtYWxsKVsyXSkNCiAgI3ByaW50KGopDQogICNpZihqPT04KSBicm93c2VyKCkNCn0NCg0KDQoNCnJlc3VsdC5mcmFtZS5zbWFsbCA8LSBkYXRhLmZyYW1lKGNvbWJpbmF0aW9uPXN1bS52YXJzLnNtYWxsLCBhdWMucC5zbWFsbD1hdWMucC5zbWFsbCwgYXVjLnZhbGlkLnNtYWxsPWF1Yy5wcmVkLnNtYWwsbnVtX29mX3ZhcnM9bnVtLm9mLnZhcnMuc21hbGwpDQoNCnJlc3VsdC5mcmFtZS5zbWFsbC5zb3J0ZWQgPC0gcmVzdWx0LmZyYW1lLnNtYWxsW29yZGVyKGF1Yy5wcmVkLnNtYWwsIGRlY3JlYXNpbmc9VFJVRSksIF0NCg0KaGVhZChyZXN1bHQuZnJhbWUuc21hbGwuc29ydGVkLCBuPTEwMCkgIyB0aGUgMTAgImJlc3QiIGNvbWJpbmF0aW9ucw0KYGBgDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg==